今天来介绍一种新的设计模式:适配器模式。
我先来举个例子:一个不懂英文的中国人去美国,和当地人交流基本上只能靠比划了,这个时候就需要一个翻译(适配器),中国人说中文,然后被翻译翻译为英语。
这样美国人就可以听明白我们在说什么了。
这里的翻译就是适配器,这里的中国人就是被适配的类,美国人不支持中国人这个接口,我们只好通过翻译这个接口让美国人支持。
UML类图:
模板:
/** * @author 陈柏宇 * 这是客户期待的接口 * 目标可以是具体的类或是抽象的类,也可以是接口 */ public abstract class Target { abstract void Request(); }
需要被适配的类:
/** * @author 陈柏宇 * 需要被适配的类 */ public class Adaptee { public void specificRequest() { System.out.println("特殊请求"); } }
适配器类:
public class Adapter extends Target{ //建立一个私有的被适配的对象 private Adaptee adaptee = new Adaptee(); /* 这样就可以实现表面上调用request()方法变成实际调用SpecificRequest()方法 */ @Override void Request() { adaptee.specificRequest(); } }
客户端:
public static void main(String[] args) { Target target = new Adapter(); target.Request(); //对客户端来说,调用的就是request方法 }
控制台输出:
特殊请求
再回到我们刚刚的那个实例,一个中国人去美国旅游需要翻译,用代码实现:
人类(美国人、中国人、翻译的基类)
public abstract class Person { protected String nation; abstract void talk(); }
美国人类:
/** * @author 陈柏宇 * 美国人类 */ public class American extends Person{ public American() { this.nation = "美国"; } @Override void talk() { System.out.println("HowDay neighbour?"); } }
中国人类:
/** * @author 陈柏宇 * 中国人类 */ public class Chinese extends Person { public Chinese() { this.nation = "中国"; } @Override void talk() { System.out.println("吃了吗,老乡?"); } }
翻译类:
/** * @author 陈柏宇 * 翻译,也就是适配器 */ public class Translator extends Person{ Chinese chinese = new Chinese(); @Override void talk() { System.out.print("中国人说 : "); chinese.talk(); System.out.print("被翻译为 : "); System.out.println("Have you eaten today , neighbour?"); } }
客户端代码:
public static void main(String[] args) { Person american = new American(); Person chinese = new Translator(); american.talk(); chinese.talk(); }
控制台输出:
HowDay neighbour?
中国人说 : 吃了吗,老乡?
被翻译为 : Have you eaten today , neighbour?
这样就可以实现在客户端不支持某一接口的情况下实现这个接口的功能了。
总结使用场景:
/** * @author 陈柏宇 * 适配器模式的使用场景: * 想使用一个已经存在的类,但如果它的接口,也就是它的方法和你的要求不相同时,就应该考虑使用适配器模式。 * 两个类所做的事情相同或相似,但是具有不同的接口要使用它。 * 这样,客户代码就可以统一的调用统一接口就行了,这样更简单,更紧凑,更直接。 * * 适配器模式不要乱用,要在双方都不太容易修改的时候使用。 * */