简体   繁体   中英

Is it an anti-pattern to use inheritance when handling RecyclerView list items?

I have two classes I want to mix and match into a recyclerView, ItemA and ItemB. In order to do this I've given them a base class of BaseItem so they can be passed in as one List. Then in my RecyclerAdapter's getItemViewType method I work out what the class is so I can use the correct Viewholder.

At this point my internal anti-pattern instincts started flaring up. I generally feel that if you have to work out what the concrete class is to handle an object then it shouldn't have a base class. Is this the wrong way to go about doing this? I've been unable to find any examples of people doing similarly.

Is there a good alternative to this? I put together some code to illustrate my point.

public class ItemRecyclerAdapter extends RecyclerView.Adapter<BaseViewHolder> {

    private FragmentManager fragmentManager;

    private static final int TYPE_A = 0;
    private static final int TYPE_B = 1;

    private final LayoutInflater inflater;
    private List<BaseItem> items;

    public ItemRecyclerAdapter(Context context, List<BaseItem> items, FragmentManager fragmentManager) {

        this.fragmentManager = fragmentManager;
        inflater = LayoutInflater.from(context);
        this.items = items;
    }

    @Override
    public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        switch (viewType) {

            case TYPE_A:

                ViewGroup v = //   Get viewGroup
                ViewHolderA viewHolderA = new ViewHolderA(v);
                return viewHolderA;

            default:

                ViewGroup defaultViewGroup = // Get viewGroup
                ViewHolderB viewHolderB = new ViewHolderB(defaultViewGroup);
                return viewHolderB;
        }
    }

    @Override
    public void onBindViewHolder(BaseViewHolder holder, int position) {
        BaseMenuItem item = items.get(position);

        switch (holder.getItemViewType()) {


            case TYPE_A:

                ViewHolderA va = (ViewHolderA) holder;
                ViewHolderA.setData((ItemA) item);

                break;

            case TYPE_B:

                ViewHolderB vb = (ViewHolderB) holder;
                ViewHolderB.setData((ItemB) item);

                break;
        }
    }

    @Override
    public int getItemViewType(int position) {
        BaseMenuItem item = items.get(position);

        boolean IsItemTypeA = item.getClass() == ItemA.class;
        if (IsItemTypeA) {
            return TYPE_A;
        }

        return TYPE_B;

    }

    @Override
    public int getItemCount() {
        if (items == null) {
            return 0;
        }

        return items.size();
    }

    public abstract class BaseViewHolder extends RecyclerView.ViewHolder {
        public BaseViewHolder(View itemView) {
            super(itemView);
        }
    }

    private class ViewHolderA extends BaseViewHolder {
        //  ViewHolder stuff here.
    }

    private class ViewHolderB extends BaseViewHolder {
        //  ViewHolder stuff here.
    }
}

I personally do not consider it an anti pattern. For those scenarios Ive implemented a pattern called delegate adapter which is a modification from an idea of this article (lecture recommended).

I do recommend though some modifications to your current implementation:

  • Specify an abstract method in BaseItem that declares its view type, and let it children implement said method. Something like getViewType that way you avoid the nasty getClass comparison.
  • Store your registered view types in a utility class or even better a IntDef definition for clearer code.

M personal opinion, is that it would be considered an anti-pattern if those two models have no logical relationship, hence not sharing any common attributes, or cannot be expressed with an abstraction.

If your only goal is to only pass in a list containing both models, pass a List<Object>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM