在现实世界中,如果想让交流电220伏特的电源给直流12伏特的笔记本供电。我们会使用AC适配器。进行电流的转化。在程序中也常常需要这样的适配器。
在程序世界中,经常会有现有的程序无法直接使用,需要做适当的变换之后才能使用。
Adapter模式:用于填补“现有程序”和“所需程序”之间差异的设计模式。
Adapter模式有以下两种:
1、类适配器模式(使用继承的适配器)
2、对象适配器模式(使用委托的适配器)。
程序示例(1)(使用继承的适配器)
package Class;
//现在是实际情况.220伏特的电源
public class Banner {
private String string;
public Banner(String string) {
this.string=string;
}
public void showWithParent() {
System.out.println("("+string+")");
}
public void showWithAster() {
System.out.println("*"+string+"*");
}
}
package Class;
//print接口。是“需求”的接口。12伏特的需求
public interface Print {
public abstract void printWeak();
public abstract void printStrong();
}
package Class;
//该类扮演适配器的角色。继承类Banner类和里面的方法。
//同时又实现了print接口
public class PrintBanner extends Banner implements Print {
public PrintBanner(String string) {
super(string);
}
public void printWeak() {
showWithParent();
}
public void printStrong() {
showWithAster();
}
}
package Class;
//通过扮演适配器觉得的printBanner类来弱化(带括号)或者强化(带星号)Hello字符串的显示
public class Main {
public static void main(String[] args) {
Print print=new PrintBanner("Hello");
print.printWeak();
print.printStrong();
}
}
这里将PrintBanner类实例保存在了Print类型的变量中,在Main类中,我们使用Print接口(即调用printWeak方法和printStrong方法)来进行编程的。对Main类代码而言,Banner类、showWithParent方法和showWithAster方法被完全隐藏起来了。这就好像笔记本电脑只要在直流12伏特电压下就能正常工作,但它并不知道12伏特的电压是由适配器将220伏特电压转换而成的。
Main类并不知道PrintBanner类是如何实现的,这样就可以不再对Main类进行修改的情况下改变PrintBanner类的具体实现。
注意使用接口类的使用原则。“不要使用具体类来编程,要优先使用抽象类和接口来编程”。
实例程序(2)(使用委托的示例程序)
关于委托:
委托:通俗来说就是“交给其他人”。在Java语言中,委托就是将某个方法中的实例处理交给其他实例的方法。(之前看到一篇文章写的是C#的委托。里面解释的是C#中因为没有函数指针这个东西,所以使用了这个委托的形式。)
Main类和Banner类与示例1完全相同。不过这里假设Print不是借口而是类。
其实这里的委托就是委托给了Bannner实例。而PrintBanner不再是继承Bannner和实现Print接口。改成了继承Print类。进而在程序中使用Banner的实例进行调用Bannner中的方法。
package Class;
//print接口。是“需求”的接口。12伏特的需求
public abstract class Print {
public abstract void printWeak();
public abstract void printStrong();
}
package Class;
//该类扮演适配器的角色。继承类Banner类和里面的方法。
//同时又实现了print接口
public class PrintBanner extends Print {
private Banner banner;
public PrintBanner(String string) {
this.banner=new Banner(string);
}
public void printWeak() {
banner.showWithParent();
}
public void printStrong() {
banner.showWithAster();
}
}
Adapter模式中的登场角色
在adapter模式中有以下登场角色
1、Target(对象)
该角色负责定义所需的方法。例:12伏特的直流电源电压。在示例程序中,由Print接口和Print类扮演此角色。
2、Clinet(请求者)
该角色负责使用Target角色所定义的方法进行具体处理。例:直流12伏特驱动的笔记本。在示例程序中,由Main类扮演此角色。
3、Adaptee(被适配)
Adaptee是一个持有既定方法的角色。例:220伏特的交流电源。在程序示例中是Bannner。
如果Adaptee角色中方法与Target角色方法相同,就不需要接下来的Adapter角色了。
4、Adapter(适配器)
Adapter模式的主人公。使用Adapter角色的方法来满足Target角色的需求,这是Adapter模式的目的,也就是Adapter角色的作用。在示例程序中是PrintBanner。
在类适配器模式中,Adapter角色通过集成来使用Adaptee角色。而在对象适配器模式中Adapter角色通过委托来使用Adapter角色。
拓展思路要点
1、什么使用使用Adapter模式
Adapter模式会对现有类进行适配,生成新的类。通过该模式可以很方便地创建我们需要的方法群。当出现bug的时候,由于我们很明确地知道了bug不在现有类(Adaptee角色)中,所以只需要扮演Adapter角色的类即可。这样一来,代码问题排查就会变得非常简单。
2、如果没有现成的代码让现有类适配新的接口时,使用Adapter模式似乎理所当然。不过实际上,我们在使用现有类适配新的接口时,常会有将这里稍微修改一下就好了。但是如果对已测试的代码进行修改,就必须重新进行测试。
使用Adapter模式可以在完全不改变现有代码的前提下使用吸纳有代码适配接口。此外,在Adapter中并非需要知道现成代码,只要知道类的功能,就可以编写出新的类。
3、版本升级与兼容
在版本升级的时候常出席那“与旧版本兼容性”问题,现实中又不能完全抛弃旧版本。这是就可以使用Adapter模式使新旧版本兼容。帮助我们轻松的维护新版本与旧版本、
例如:今后只想维护新版本,就可以让新版本扮演Adaptee的角色,旧版本扮演Target的角色。接着编写Adapter角色的类,让它使用新版本来实现旧版本的类的方法。
相关的模式
1、Bridge模式
Adapter模式用于连接接口不同的类,而Bridge模式则用于连接类的功能层次结构与实现层次结构。
2、Decorator模式
Adapter用于填补不用接口之间的缝隙,而Decorator,模式则是在不改变接口的前提下增加功能。