前言
与电源适配器相似,在适配器模式中引入了一个被称为适配器(Adapter)的包装类,而它所包装的对象称为适配者(Adaptee),即被适配的类。适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用。
也就是说:当客户类调用适配器的方法时,在适配器类的内部将调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类。因此,适配器让那些由于接口不兼容而不能交互的类可以一起工作。
定义:将一个类的接口转换成客户希望的另外一个接口。原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适配器模式也被称为:包装器(Wrapper)模式;变压器模式。
适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
优点
可以让两个没有关系的类,兼容在一起运行
增加类的透明度,复用度,灵活性好
组成角色
- 目标角色(Target)
- 适配器角色(Adapter)
- 被适配角色(Adaptee)
例一
//Target角色
public interface FiveVolt {
public int getVolt5();
}
//Adaptee角色
public class Volt220 {
public int getVolt220(){
return 220;
}
}
类适配器
//Adapter角色
public class VoltAdapter extends Volt220 implements FiveVolt{
@Override
public int getVolt5() {
return 5;
}
}
对象适配器
//Adapter 角色
public class VoltAdapter implements FiveVolt{
Volt220 volt220;
public VoltAdapter(Volt220 volt220) {
this.volt220 = volt220;
}
@Override public int getVolt5() {
return 5;
}
public int getVolt220(){
return volt220.getVolt220();
}
}
使用
public abstract class ItemAdapter<T> {
//绑定View的数据源
private List<T> mDatas;
public ItemAdapter(List<T> datas) {
if (datas == null) datas = new ArrayList<>(0);
mDatas = datas;
}
public ItemAdapter(T[] datas) {
mDatas = new ArrayList<>(Arrays.asList(datas));
}
// 需要用户来定义的 view ,
protected abstract View getView(ViewGroup parent, int position, T t);
// 获取每个Item
protected T getItem(int position) {
return mDatas.get(position);
}
// 获取数据源的大小
protected int getCount() {
return mDatas.size();
}
// 注册数据源变化的监听器
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
// 移除监听器
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
private final DataSetObservable mDataSetObservable = new DataSetObservable();
// 通知数据源 更新
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
}
获取数据
public class Linear extends LinearLayout {
private ItemAdapter mItemAdapter;
private DataSetObserver mDataSetObserver = new DataSetObserver() {
@Override public void onChanged() {
super.onChanged();
onChange();
}
@Override public void onInvalidated() {
super.onInvalidated();
}
};
private void onChange() {
if (null == mItemAdapter) return;
int count = mItemAdapter.getCount();
for (int i = 0; i < count; ++i) {
View view = mItemAdapter.getView(this, i, mItemAdapter.getItem(i));
addView(view);
}
}
public void setAdapter(ItemAdapter itemAdapter) {
if (mItemAdapter != null && mDataSetObserver != null) {
mItemAdapter.unregisterDataSetObserver(mDataSetObserver);
}
this.mItemAdapter = itemAdapter;
if (null != mItemAdapter) {
mItemAdapter.registerDataSetObserver(mDataSetObserver);
mItemAdapter.notifyDataSetChanged();
}
}
//....
}
例二
目标角色(Target)
/**
* 定义Client 使用的接口。与特定领域相关。<br>
* Target 与 Adaptee 没有任何关系;Adaptee和Target中的方法既可以相同,也可以不同
*/
public interface Target {
/**
* 示意方法,客户端请求处理的方法
*/
public void request();
}
适配器角色(Adapter)
- 组合被适配的角色
- 重写目标接口方法,中间调用被适配的角色的方法实现
适配器角色:这个适配器模式的核心。它将被适配角色已有的接口转换为目标 角色希望的接口。
分类:将适配器模式分为类适配器模式和对象适配器模式。 区别在于被适配的角色通过继承完成的还是通过组合来完成的。(不提倡继承)
public class Adapter implements Target {
/**
* 持有需要被适配的接口对象
*/
private Adaptee adaptee;
/**
* 构造方法,传入需要被适配的对象
* 需要被适配的对象
*/
public Adapter(Adaptee adaptee) { // 组合的方式
this.adaptee = adaptee;
}
实现目标接口重写的方法
public void request() {
System.out.println("this is in Adapter!");
// 可能转调已经实现了的方法,进行适配
adaptee.specificRequest();
}
}
被适配角色(Adaptee)
被适配的角色:这个角色有一个已存在并使用了的接口,而这个接口是需要我们适配的
public class Adaptee {
/**
* 示意方法,原本已经存在,已经实现的方法
*/
public void specificRequest() {
// 具体的功能处理
System.out.println("this is in Adaptee!");
}
}
适配器模式(转换器):将一个类的接口转换成客户希望的另外一个接口。原本由于接口不兼容而不能一起工作的那些类可以一起工作。
- 组成:目标角色;被适配角色;适配器角色
- 与代理模式的区别:在于代理模式应用的情况是不改变接口命名的, 而且是对已有接口功能的一种控制;而适配器模式则强调接口转换。
public class AdapterPattern {
public static void main(String[] args) {
// 将调用适配器,转换到调用被适配的接口
Target target = new Adapter(new Adaptee());
target.request();
}
总结
- 目标角色(Target)
- 适配器角色(Adapter)
- 被适配角色(Adaptee)
目标角色是个男孩,想要一个羽毛球,但是他没有。但是被适配角色有羽毛球。所以借助适配角色重写了目标角色的需要方法,然后又注入被适配角色的羽毛球。在调用目标角色的时候,把羽毛球给他。这男孩很高兴,说这叫适配器模式