Java设计模式之结构型—适配器模式
Java中最常用的设计模式-CSDN博客
类适配器(使用继承)
目标接口
// 客户期望的 5V 直流电
public interface Dc5V {int output5V();
}
被适配者
// 家里只有 220V 交流电
public class Ac220V {public int output220V() {System.out.println("输出交流 220V");return 220;}
}
适配器
// 用“继承”把 220V 转成 5V
public class PowerAdapter extends Ac220V implements Dc5V {@Overridepublic int output5V() {int src = output220V(); // 拿到 220Vint dst = src / 44; // 降压System.out.println("输出直流 5V");return dst;}
}
测试
public class Main {public static void main(String[] args) {Dc5V dc5V = new PowerAdapter();dc5V.output5V(); // 客户只关心 Dc5V 接口}
}
对象适配器(使用组合/委派,推荐)
目标接口 & 被适配者同上,不再重复。
适配器
// 用“组合”把 220V 转成 5V
public class PowerObjectAdapter implements Dc5V {private final Ac220V ac220V; // 组合优于继承public PowerObjectAdapter(Ac220V ac220V) {this.ac220V = ac220V;}@Overridepublic int output5V() {int src = ac220V.output220V();int dst = src / 44;System.out.println("输出直流 5V");return dst;}
}
测试
public class Main {public static void main(String[] args) {Dc5V dc5V = new PowerObjectAdapter(new Ac220V());dc5V.output5V();}
}
接口适配器(缺省适配器 / 抽象适配器)
当接口方法太多,而客户只想实现其中 1~2 个时,用抽象类先空实现全部方法。
目标接口
public interface AllEventListener {void onClick();void onDoubleClick();void onLongPress();
}
抽象适配器
public abstract class MouseAdapter implements AllEventListener {public void onClick() { /* 空实现 */ }public void onDoubleClick() { /* 空实现 */ }public void onLongPress() { /* 空实现 */ }
}
具体使用者
public class MyMouseListener extends MouseAdapter {@Overridepublic void onClick() {System.out.println("我只关心单击事件");}
}
测试
public class Main {public static void main(String[] args) {AllEventListener listener = new MyMouseListener();listener.onClick(); // 只触发单击}
}
-
类适配器:继承被适配者,简单但高耦合。
-
对象适配器:组合被适配者,灵活可复用,推荐。
-
接口适配器:抽象类空实现大接口,子类按需覆写,解决“接口污染”。
RecyclerView.Adapter
RecyclerView.Adapter
使用的是 对象适配器(Object Adapter) 这一经典形式
为什么这样归类
-
它通过 组合 而非继承来持有并操作“被适配的数据源”:
你把任何List<T>
(或其它数据结构)组合进自定义的 Adapter 里,Adapter 再把它“适配”成 RecyclerView 能识别的ViewHolder
序列。 -
没有修改数据源类本身,也没有要求数据源继承任何父类;Adapter 只实现
RecyclerView.Adapter
这一“目标接口”,把数据→视图的转换细节封装在onBindViewHolder()
等方法中。 -
如果数据源接口不兼容(例如从数据库 Cursor 到对象模型),再包一层 对象适配器 即可,同样采用组合方式。
简记:
RecyclerView.Adapter = 典型的 对象适配器模式(组合 + 委派)。
RecyclerView.Adapter在RecyclerView中的调用
把 RecyclerView 和 Adapter 的交互画成一条 时间线,你就能一眼看清 “Adapter 是在哪些时机、被谁、以什么顺序调用的”。
RecyclerView
├─ LayoutManager (测量/布局)
├─ Recycler (ViewHolder 缓存池)
└─ Adapter (数据 & ViewHolder 工厂)
首次布局
┌────────────┐ ┌──────────────┐
│ getItemCount│ ←── LayoutManager ──┤ onMeasure │
└────┬───────┘ └──────────────┘
│ ┌────────────────┐
│ 没有缓存 │ onLayoutChildren│
↓ └──────┬─────────┘
┌────────────┐ │
│onCreateVH │ ←── RecyclerView ─────────┘
└────┬───────┘
│ 得到空壳 ViewHolder
↓
┌────────────┐
│onBindVH │ ←── RecyclerView(把数据塞进壳里)
└────────────┘
-
LayoutManager 是“导演”,它决定什么时候需要 ViewHolder、需要多少。
-
RecyclerView 是“中介”,把 LayoutManager 的需求翻译成对 Adapter 的调用。
-
Adapter 只负责两件事:
-
告诉你“一共有多少条”(getItemCount)
-
按需生产 & 绑定 ViewHolder(onCreateViewHolder / onBindViewHolder)
-
RecyclerView.Adapter的onCreateViewHolder是适配器模式,onBindViewHolder观察者模式
-
onCreateViewHolder → 体现“适配器模式”
职责:把“数据层”无法直接使用的布局/视图,转换成 RecyclerView 需要使用的 ViewHolder。
这正是适配器模式的本质:接口转换——把LayoutInflater.inflate()
得到的原始View
,转换成符合 RecyclerView 接口要求的ViewHolder
。 -
onBindViewHolder → 体现“观察者模式(或更广义的数据绑定)”
职责:当数据源(被观察者)发生变化时,由 RecyclerView 框架主动回调 Adapter,把最新数据“推”给对应的 ViewHolder。
虽然 RecyclerView 内部并没有显式使用java.util.Observable/Observer
,但“数据源变化 → notifyXXX → 系统回调 onBindViewHolder”这一套流程,完全符合 观察者模式 的“发布-订阅”思想:
• 数据是“被观察者”
• Adapter/ViewHolder 是“订阅者”
• notifyItemRangeChanged 等方法就是“发布事件”
一句话总结
-
onCreateViewHolder:完成 视图→ViewHolder 的适配,属于 适配器模式 的具体实现点。
-
onBindViewHolder:完成 数据→视图的同步,体现了 观察者模式 的“推数据”行为。