标签:
本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/51570748
适配器模式将一个类的接口,转换成客户期望的另一个接口。适配器让原本不兼容的类可以合作无间。(摘自Head First中文版243页)
通常情况下的适配器模式有两种形式:对象适配器和类适配器。类的适配器模式采用继承实现,而对象适配器采用对象组合方式实现。
类适配器使用继承的方式(静态方式),这样就使得适配器不能和Adaptee的子类一起工作。当目标类数量随着业务需求变得越来越多时,会使得代码结构变得复杂,以至于难以维护;对象适配器使用对象组合的方式(动态组合方式),一个适配器可以把多种不同的源适配到同一个目标,即同一个适配器可以把源类和源类的子类都适配到目标接口。所以在实际情况下,建议尽量多使用对象适配器的实现方式,即多用组合、少用继承。但是对于具体的问题,还是需要选择合适的方式去实现。
那什么时候使用适配器模式呢?一种情况是,你想使用一个已经存在的类,而其接口不符合你的需求。你打算创建一个可以复用的类,该类可以与其它不相关的类或不可预见的类(即接口间不兼容的类)协同工作,则可以考虑使用适配器模式。另一种情况是,你想使用一些已经存在的类,但是不可能对每一个类都子类化以匹配它们的接口,这时可以考虑使用(对象)适配器模式(对象适配器可以适配它的父类接口)。
目标接口(Target):客户所期待的接口,具体类、抽象类、接口。
待适配的类(Adaptee):需要适配的类。
适配器(Adapter):包装一个需要适配的对象,把原接口转换成目标接口。
类适配器示例如下所示:
package headfirst.design.adapter.extend;
/**
* 已存在的、具有特殊功能、但不符合我们既有的标准接口的类
*/
public class Adaptee {
public void specialMethod() {
System.err.println("这是一个经过适配的特殊的方法");
}
}
package headfirst.design.adapter.extend;
/**
* 定义客户端期待的接口
*/
public interface Itarget {
public void method();
}
package headfirst.design.adapter.extend;
/**
*适配器,表面上调用method()方法,实际调用specialMethod()
*/
public class Adapter extends Adaptee implements Itarget{
@Override
public void method() {
super.specialMethod();
}
}
package headfirst.design.adapter.extend;
public class Test {
public static void main(String[] args) {
Itarget adapter = new Adapter();
adapter.method();
}
}
对象适配器示例如下所示:
package headfirst.design.adapter;
/**
* 男人相关接口
*/
public interface IMen {
public void run();
public void sleep();
public void groupBaby();
}
package headfirst.design.adapter;
/**
* 具体类
*/
public class Men implements IMen {
@Override
public void run() {
System.err.println("Men run fast");
}
@Override
public void sleep() {
System.err.println("Men want sleep");
}
@Override
public void groupBaby() {
System.err.println("men can group baby");
}
}
package headfirst.design.adapter;
/**
* 女人相关接口
*
*/
public interface IWomen {
public void womenrun();
public void womensleep();
public void womencreatBaby();
}
package headfirst.design.adapter;
/**
* 具体类
* @author liqqc
*
*/
public class Women implements IWomen {
@Override
public void womenrun() {
System.err.println("women run slow");
}
@Override
public void womensleep() {
System.err.println("women need to sleep");
}
@Override
public void womencreatBaby() {
System.err.println("women can create baby");
}
}
package headfirst.design.adapter;
/**
* 将男人进行适配
*
*/
public class Adapter implements IWomen {
private IMen men;
public Adapter(IMen men) {
super();
this.men = men;
}
@Override
public void womenrun() {
men.run();
}
@Override
public void womensleep() {
men.sleep();
}
@Override
public void womencreatBaby() {
men.groupBaby();
}
}
package headfirst.design.adapter;
public class Test {
public static void main(String[] args) {
Men men = new Men(); //创建一个男人
Women women = new Women(); //创建一个女人
IWomen awomen = new Adapter(men);//将男人包装到一个女人适配器,让他看起来像女人
awomen.womenrun();
awomen.womensleep();
awomen.womencreatBaby();
System.err.println("women....");
women.womenrun();
women.womensleep();
women.womencreatBaby();
}
}
Console:
Men run fast
Men want sleep
men can group baby
women....
women run slow
women need to sleep
women can create baby
Java IO 中主要使用了两种设计模式:装饰者模式和适配器模式。在前面的一篇文章中已阐述了装饰者模式。这里将简单阐述下Java IO中的适配模式。查看IO源码可以发现:
public class InputStreamReader extends Reader {
private final StreamDecoder sd;
/**
* Creates an InputStreamReader that uses the default charset.
*
* @param in An InputStream
*/
public InputStreamReader(InputStream in) {
super(in);
try {
sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
} catch (UnsupportedEncodingException e) {
// The default encoding should always be available
throw new Error(e);
}
}
InputStreamReader 的构造方法中传入的是InputStream,说明将InputStream转换成了Reader,而StreamDecoder的设计实现实际上采用了适配器模式。所以我们常说InputStreamReader和OutputStreamWriter做了InputStream/OutputStream字节流类到Reader/Writer之间的转换,即InputStreamReader和OutputStreamWriter是字节流通向字符流的桥梁
适配器模式的优点:复用性好。系统需要使用已有的类,而该类接口不符合系统当前的需要,则可通过适配器模式让这些功能得到更好的复用。扩展性好。在实现适配器功能时,可以依据需求增加功能,进而自然地扩展系统的功能。
适配器模式的缺点:项目中过多的使用适配器,会让系统代码变得零乱,不好整体把握系统。例如,在某个业务中表面上看到调用的是接口A,但其实其内部被适配成了接口B的实现,如果太多出现这种情况,那么系统面临的将是一场灾难。一般情况下,如果不是非常有必要,最好不使用适配器,而是对系统进行相应的重构。
本文只是简单介绍了适配器模式,并未对其进行深入探讨,略显粗糙。希望本文对你有所帮助。
标签:
原文地址:http://blog.csdn.net/pistolove/article/details/51570748