Adapter模式属于结构型设计模式
设计思想: 将一个类的接口转换成客户希望的另外一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
Adpater模式又分为如下2类:
1.类的适配器模式,采用继承实现
2.对象适配器模式,采用对象组合方式实现
Adapter模式的类图结构:
Adapter模式存在4种角色:
1.目标抽象角色(Target):客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口
2.源角色(Adaptee): 也是被适配的角色
3.适配器角色(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口
4,客户端(Client)
下面通过一个可以同时使用电压220V和110V的适配器场景例子,来体会下Adapter模式的设计思想
(1)类的适配器模式
Adaptee.java源角色
package huahua.pattern1;
/**
* @author huahua
* 源角色也是被适配角色
*/
public class Adaptee {
public int get220v()
{
return 220;
}
}
Target.java目标角色
package huahua.pattern1;
/**
* @author huahua
* 目标抽象角色
*/
public interface Target {
public int get110v();
public int get220v();
}
Adapter.java适配器角色
package huahua.pattern1;
/**
* @author huahua
* 类适配器模式的适配器角色
* (采用继承实现)
*/
public class Adapter extends Adaptee implements Target{
@Override
public int get110v() {
// TODO Auto-generated method stub
return 110;
}
}
MainActivity.java客户端角色
package huahua.adapterpattern;
import huahua.pattern1.Adaptee;
import huahua.pattern1.Adapter;
import huahua.pattern1.Target;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
/**
* @author huahua
* 客户端角色
*/
public class MainActivity extends Activity {
private Button btn1;
private Button btn2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1 = (Button)findViewById(R.id.btn1);
btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Target target = new Adapter();
Toast.makeText(MainActivity.this ,"面向类的适配器模式:"+target.get110v()+"和"+target.get220v(), Toast.LENGTH_SHORT).show();
}
});
btn2 = (Button)findViewById(R.id.btn2);
btn2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Target target = new huahua.pattern2.Adapter(new Adaptee());
Toast.makeText(MainActivity.this, "面向对象的适配器模式:"+target.get110v()+"和"+target.get220v(), Toast.LENGTH_SHORT).show();
}
});
}
}
可以看到在MainActivity.java的btn1响应中220V和110V的电压都能得到。上述代码使用面向类的适配器模式,通过适配器角色Adapter扩展了源角色Adaptee,从而同时满足使用220V和110V电压的要求。这类适配器模式主要用于单一的为某个类而实现适配。这里有人会说,为什么不在源角色Adaptee中直接添加get110v()方法呢?其实,这正是适配器模式的精髓所在:为实现某种目的而为源类暂时性的扩展加上某个方法,所以不能破坏源类的结构。同时这也符合Java高内聚,低耦合,开闭原则的要求。
(2)对象适配器模式
和类的适配器模式不同的是对象适配器模式是把源Adaptee作为一个对象聚合到适配器Adapter类,其中源Adaptee和目标Target不变,只用改变Adapter类就行了
Adapter.java
package huahua.pattern2;
import huahua.pattern1.Adaptee;
import huahua.pattern1.Target;
/**
* @author huahua
* 对象适配器模式的适配器角色
* (采用对象组合方式实现)
*/
public class Adapter implements Target{
Adaptee adaptee;
public Adapter(Adaptee adaptee)
{
this.adaptee = adaptee;
}
public int get220v()
{
return adaptee.get220v();
}
@Override
public int get110v() {
// TODO Auto-generated method stub
return 110;
}
}
上述对象适配器模式中,把源Adaptee作为一个构造参数传入适配器,然后执行接口所要求的方法,这种适配器模式可以为多个源进行适配,弥补了类适配器的不足。
整个例子的代码结构如下:
接下来对这2种适配器模式做一个总结:
1.类适配器模式用于单一源的适配,由于它的源的单一化,代码实现不用写选择逻辑,很清晰
2.对象适配器模式可用于多源的适配,使得原本用类适配器模式需要写很多适配器的情况不复存在,弱点是,源数目可能比较多,所以具体实现条件选择分支比较多,不太清晰
最后来说下适配器模式的优点
1.通过适配器,客户端可以调用同一接口,因而对客户端来说是透明的。这样做更简单、更直接、更紧凑。
2.复用了现存的类,解决了现存类和复用环境要求不一致的问题。
3.将目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,而无需修改原有代码。
4.一个对象适配器可以把多个不同的适配者类适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口
在做项目的时候,自己会有一些以写好不错的类,适配器模式可以把过去的类换个包装重新建立出需要的类,这个模式可以帮你节省建立必要方法组群的时间,以便减轻写程序的负担和工作量
有兴趣的朋友可以下载源码,例子源码写的非常简单,主要就是阐述适配器模式的设计思想
源码下载地址