Java设计模式 - 适配器模式
概念:
将一个类的接口,转换成客户期望的另一个接口。适配器模式让原来接口不兼容的类可以在一起工作。
解决的问题:
提供类似于中间人的作用:把原本不兼容、不能一起工作的接口组合在一起,使得它们能够在一起正常的工作。
模式结构:
有两种适配器模式:对象适配器和类适配器。
因为类适配器需要使用到多重继承,而Java不支持多重继承,所以本文就只对对象适配器进行解释。
模式中的角色:
Target(目标接口):客户请求的接口。Adapter必须要实现这个接口(也可以是抽象类)。
Adapter(适配器类):实现Target接口,组合用户所需要的类。
Adaptee(被适配者):请求最终的执行者。
UML图:
这种适配器模式充满着良好的OO设计原则:使用对象组合,以修改的接口包装被适配者:这种做法还有额外的优点,那就是,被适配者的任何子类,都可以搭配着适配器使用。
情景导入:
某个玩具厂商的用户需要一种能学鸭子叫的玩具鸡,怎么办?
厂商想这还不容易:我只要生产一个玩具鸡的外形,将它的发音功能委托生产玩具鸭的生产线负责。也就是说:外表看上去是玩具鸡,但发音这个功能有玩具鸭实现。
1 package com.tony.Adapter;
2
3 /**
4 * Target接口,接收用户请求。
5 * 玩具鸡
6 */
7 public interface Chicken {
8
9 void speak();
10 }
1 package com.tony.Adapter;
2
3 /**
4 * 玩具鸭接口
5 * 面向接口编程是一种好习惯
6 */
7 public interface Duck {
8
9 void speak();
10 }
1 package com.tony.Adapter;
2
3 /**
4 * Adapter
5 * 玩具鸡适配器,将发音请求委托给玩具鸭。
6 */
7 public class ChickenAdapter implements Chicken {
8
9 private Duck duck;
10
11 public ChickenAdapter(){
12 duck = new ToyDuck();
13 }
14 @Override
15 public void speak() {
16 duck.speak();
17 }
18
19 }
1 package com.tony.Adapter;
2
3 /**
4 * Adaptee
5 * 被适配者,请求的真正执行者。
6 */
7 public class ToyDuck implements Duck{
8
9 @Override
10 public void speak() {
11 System.out.println("I'm duck, ga ga ga...");
12 }
13
14 }
1 package com.tony.Adapter;
2
3 public class Test {
4 public static void main(String[] args) {
5 Chicken toyChicken = new ChickenAdapter();
6 toyChicken.speak();
7 }
8 }
客户使用适配器的过程:
1、客户通过目标接口调用适配器的方法对适配器发出请求。
2、适配器使用被适配者接口吧请求转换成适配者的一个或多个调用接口。
3、客户接受到调用的结果,但并未察觉这一切是适配器在起转换作用。
其实说了这么多都是为了说明一件事:适配器就是将客户的请求委托给其它能够完成该功能的类!只是起到了一个中转的作用!
模式总结:
优点:
提高代码重用率。使原本不能在实际情况下使用的类通过适配器又可以正常工作。
当需求发生改变时,只需要改变被适配者,无需改动其它任何代码。这对客户端是透明的,使得代码更加简洁。
被适配者的任何子类都可以搭配适配器使用。
适用场景:
当两个毫不相关的类需要在一起工作。
需要使用别人的接口而又不想改动自己的代码。
旧系统升级等等。
其他模式:设计模式专栏
参考文献:
《Head First 设计模式》