• 设计模式 --- 适配器模式 Adapter Pattern


    什么是适配器模式

    • 适配器可以使两个接口兼容, 也就是通过一个接口实现另外一个接口的方法
    • 比如现在有一个接口叫 AnimalRobot, 并且有两个方法: cry() 和 move. 还有一个接口叫 Dog, 也有两个方法叫 run() 和 bark(). 现在需要使用Dog实现AnimalRobot接口, 但是两个接口完全不兼容. 此时可以使用适配器实现接口兼容
    • 适配器模式主要由三部分组成
    • Target: 目标接口 (上面的AnimalRobit)
    • Source: 被适配接口. (上面的Dog接口)
    • Adapter: 对Adaptee接口与Target进行适配
    • 假设现在有下面两个接口需要适配

    Source 接口及实现类

    public interface IAC220 {
    	void output220V();
    }
    
    public class AC220 implements IAC220 { 
        public int output220V(){
            int output = 220;
            return output;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    Target目标接口

    public interface DC5 {
        int output5V();
    }
    
    • 1
    • 2
    • 3

    类适配器 ClassAdapter

    • 适配器与适配者之间是继承(或实现)关系
    • 适配器继承被适配类, 实现目标接口
    • 适配器在重写目标接口的方法里使用父类方法实现适配
    • 缺点: 因为java单继承的缘故,target类必须是接口,以便于Adapter去继承Source并实现target,完成适配的功能,但这样就导致了Adapter里暴露了Source类的方法,使用起来的成本就增加了
    public class PowerAdapter extends AC220 implements DC5 {
        @Override
        public int output5V() {
            int output = output220V();
            return (output / 44);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    对象适配器 ObjectAdapter

    • 对于同样的逻辑,我们在以对象适配器模式实现。我们保留AC220和DC5两个基本类,我们让Adapter持有source类的实例,然后再实现DC5,以这种持有对象的方式来实现适配器功能
    public class PowerAdapter implements DC5{
        private AC220 mAC220;
    
        public PowerAdapter(AC220 ac220){
            this.mAC220 = ac220;
        }
    
        @Override
        public int output5V() {
            int output = 0;
            if (mAC220 != null) {
                output = mAC220.output220V() / 44;
            }
            return output;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    接口适配器模式

    • 对于接口适配器模式,我们就不用担着眼于220->5,我们的接口可以有更多的抽象方法
    • android开发中用的很多
    public interface DCOutput {
        int output5V();
        int output9V();
        int output12V();
        int output24V();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    设置一个中间适配器,用于实现默认的接口方法

    /**
     * Created by italkbb on 2018/1/24.
     * 这里抽象类其实就写了空方法,等着子类去实现需要的方法。
     */
     
    public abstract class PowerAdapter implements DCOutput{
        protected AC220 mAC220;
    
        public PowerAdapter(AC220 ac220){
            this.mAC220 = ac220;
        }
    
        @Override
        public int output5V() {
            return mAC220.output220V();
        }
    
        @Override
        public int output9V() {
            return mAC220.output220V();
        }
    
        @Override
        public int output12V() {
            return mAC220.output220V();
        }
    
        @Override
        public int output24V() {
            return mAC220.output220V();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    这样一来我们就只需要重写父类我们关心的方法了

    private void initinterfaceAdapter() {
            // 使用匿名类重写需要重写的方法
            interfaceadapter.PowerAdapter powerAdapter = new PowerAdapter(new AC220()) {
                @Override
                public int output5V() {
                    int output = 0;
                    if (mAC220 != null) {
                        output = mAC220.output220V() / 44;
                    }
                    return output;
                }
            };
            powerAdapter.output5V();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    适配器模式在安卓开发中的例子

    RecyclerView

    • 使用适配器完成自定义cardview
    • 需要将restaurantCardArrayList (也就是ArrayList) 适配RecyclerView
    • 使用对象适配器, source: ArrayList , target: RecyclerView,
    • 使用ArrayList实现target中的onBindViewHolder, onCreateViewHolder等方法
    public class RestaurantAdapter extends RecyclerView.Adapter<RestaurantAdapter.Viewholder> implements View.OnClickListener{
    
        private Context context;
        private ArrayList<RestaurantCard> restaurantCardArrayList;
        private static final String TOKEN = "RO1Oxxrhr0ZE2nvxEvJ0ViejBTWKcLLhPQ7wg6GGPlGiHvjwaLPU2eWlt4myH3BC1CP4RSzIQ7UCFjZ-FBaF_4ToUYHfs6FF6FwipyMuz47xVvlpEr6gDv-2YRQUYnYx";
        private RecyclerViewOnItemClickListener onItemClickListener;
    
        public class Viewholder extends RecyclerView.ViewHolder {
            private ImageView restaurantImage, starSymbol;
            private TextView restaurantTitle, restaurantContent, restaurantRating;
            private View root;
    
            public Viewholder(@NonNull View root) {
                super(root);
                this.root = root;
    
                restaurantImage = root.findViewById(R.id.restaurant_image);
                restaurantTitle = root.findViewById(R.id.restaurant_title);
                restaurantContent = root.findViewById(R.id.restaurant_content);
                restaurantRating = root.findViewById(R.id.rating);
                starSymbol = root.findViewById(R.id.star);
            }
        }
    
        // Constructor
        public RestaurantAdapter(Context context, ArrayList<RestaurantCard> restaurantCardArrayList) {
            this.context = context;
            this.restaurantCardArrayList = restaurantCardArrayList;
        }
    
        @NonNull
        @Override
        public RestaurantAdapter.Viewholder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View root = LayoutInflater.from(parent.getContext()).inflate(R.layout.restaurant_cardview_item, parent, false);
            Viewholder vh = new Viewholder(root);
            root.setOnClickListener(this);
            return new RestaurantAdapter.Viewholder(root);
        }
    
        @Override
        public void onBindViewHolder(@NonNull RestaurantAdapter.Viewholder holder, int position) {
            RestaurantCard model = restaurantCardArrayList.get(position);
            holder.restaurantContent.setText(model.getContent());
            if (model.getTitle().length() > 24){
                model.setTitle(model.getTitle().substring(0, 24) + "...");
            }
            holder.restaurantTitle.setText(model.getTitle());
            holder.starSymbol.setImageResource(R.drawable.ic_baseline_star_24);
            holder.restaurantRating.setText(Float.toString(model.getRating()));
    
            Log.d("From RestaurentAdapter onBindViewHolder", "glide next");
            if (model.getRestaurantImageUrl().toString().length() != 0) {
                GlideUrl glideUrl = new GlideUrl(model.getRestaurantImageUrl(), new LazyHeaders.Builder()
                        .addHeader("Authorization", " Bearer " + TOKEN)
                        .build());
                Glide.with(this.context).load(glideUrl).into(holder.restaurantImage);
            }
            else {
                Log.d("From RestaurentAdapter onBindViewHolder", "getRestaurantImageUrl() is empty");
            }
            holder.root.setTag(position);
        }
    
        @Override
        public int getItemCount() {
            return restaurantCardArrayList.size();
        }
    
    
        @Override
        public void onClick(View view) {
            if (onItemClickListener != null) {
                // Use getTag() to get data
                onItemClickListener.onItemClickListener(view, (Integer) view.getTag());
            }
        }
    
        public void setRecyclerViewOnItemClickListener(RecyclerViewOnItemClickListener onItemClickListener) {
            this.onItemClickListener = onItemClickListener;
        }
    
        public interface RecyclerViewOnItemClickListener {
    
            void onItemClickListener(View view, int position);
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88

    将Adapter传入recyclerView使用

    RestaurantAdapter restaurantAdapter = new RestaurantAdapter(getActivity(), restaurantCardArrayList);
    recyclerView.setAdapter(restaurantAdapter);
    
    • 1
    • 2

    ListView

    • 接口适配器模式
    • ArrayAdapter有很多包含很多方法, 比如下面的方法
    @Override
        public int getCount() {
            return mObjects.size();
        }
    
        @Override
        public @Nullable T getItem(int position) {
            return mObjects.get(position);
        }
    
        /**
         * Returns the position of the specified item in the array.
         *
         * @param item The item to retrieve the position of.
         *
         * @return The position of the specified item.
         */
        public int getPosition(@Nullable T item) {
            return mObjects.indexOf(item);
        }
    
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        @Override
        public @NonNull View getView(int position, @Nullable View convertView,
                @NonNull ViewGroup parent) {
            return createViewFromResource(mInflater, position, convertView, parent, mResource);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    使用内部匿名类实现其中需要的方法

    listview.setAdapter(new ArrayAdapter<String>(this, R.layout.list_item, list) {
                @Override
                public View getView(int position, View convertView, ViewGroup parent) {
                    View view = super.getView(position, convertView, parent);
                    TextView textView = (view.findViewById(R.id.listItem));
                    textView.setMinHeight(0);
                    textView.setMinimumHeight(0);
                    textView.setHeight(height/ items.length);
                    return view;
                }
            });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    【线性代数基础进阶】向量-part3
    【ESP-S3-BOX-Lite花屏问题】:Github下载源码(出厂源码factory_demo)编译调试到ESP-S3-BOX-Lite中出现花屏现象
    5.2 磁盘CRC32完整性检测
    安卓手机APP开发__媒体开发部分__播放器的接口
    Spring中@Valid和@Validated有哪些不同呢?
    博弈论——博弈信息结构
    MySQL如何改进LRU算法
    【分享】小红书采集图片下载到本地
    梦笔记2022-1122
    暑期JAVA学习(47)XML解析技术
  • 原文地址:https://blog.csdn.net/weixin_38803409/article/details/126646883