bboyjing's blog

HeadFirst设计模式七【适配器模式】

还记得之前学的装饰者模式,是将对象包装起来,赋予它们新的职能。而这一篇要学的适配器模式目的相反,包装某些对象,让他们的接口看起来不像自己而像是别的东西。因为这样就可以在设计中,将类的接口转换成想要的接口。下面就来具体看看。

场景描述

先说一说现实中的场景最典型的一个适配器场景,就是插座。我们国内的、欧洲的、美国的插座可能都不一样,出国的时候买的转接头,就是适配器。比如去欧洲,它插在国内的插头和欧洲的插座之间,不用改任何一方就实现了适配。这里的话,用策略模式的鸭子们来模拟一个场景,假设需要很多鸭子对象,鸭子不够了。手边有一个新的物种,火鸡,它有自己的接口。因为火鸡的接口不同,所以我们不能公然拿来用,那我们看下适配器模式在这个场景下是如何工作的。

代码示例

简单的火鸡适配鸭子的场景

  1. 鸭子接口,以及实现

    1
    2
    3
    4
    5
    public interface Duck {
    public void quack();
    public void fly();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class MallardDuck implements Duck {
    @Override
    public void quack() {
    System.out.println("Quack");
    }
    @Override
    public void fly() {
    System.out.println("I'm flying");
    }
    }
  2. 火鸡接口,以及实现

    1
    2
    3
    4
    5
    public interface Turkey {
    public void gobble();
    public void fly();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class WildTurkey implements Turkey {
    @Override
    public void gobble() {
    System.out.println("Gobble gobble");
    }
    @Override
    public void fly() {
    System.out.println("I'm flying a short distance");
    }
    }
  3. 实现火鸡适配器,需要实现想转换成的类型接口,这里就是鸭子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    public class TurkeyAdapter implements Duck {
    /**
    * 适配器对象
    */
    Turkey turkey;
    public TurkeyAdapter(Turkey turkey) {
    this.turkey = turkey;
    }
    /**
    * 将gobble接口转换成quack接口
    */
    @Override
    public void quack() {
    turkey.gobble();
    }
    /**
    * 虽然两个接口都具备fly行为,但是火鸡飞行距离短
    * 假设火鸡连续飞5次跟鸭子一样
    */
    @Override
    public void fly() {
    for (int i = 0; i < 5; i++) {
    turkey.fly();
    }
    }
    }
  4. 测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class Test {
    public static void main(String[] args) {
    MallardDuck duck = new MallardDuck();
    WildTurkey turkey = new WildTurkey();
    Duck turkeyAdapter = new TurkeyAdapter(turkey);
    System.out.println("The Turkey says...");
    turkey.gobble();
    turkey.fly();
    System.out.println("\nThe Duck says...");
    testDuck(duck);
    System.out.println("\nThe TurkeyAdapter says...");
    testDuck(turkeyAdapter);
    }
    static void testDuck(Duck duck) {
    duck.quack();
    duck.fly();
    }
    }

总结

这个模式看似还挺简单的,重点是要回顾下适配器模式和装饰模式的区别。从目的上来说的话:装饰模式是不改变接口,但是添加责任,就是那种配料无限装饰奶茶,算出价格;适配器模式则是将一个接口转换成另一个接口,就好比这里的硬把火鸡转换成鸭子给客户使用。最后,要引出一种新模式,这个模式的目的是改变接口,但是它改变接口的原因是为了简化接口。这个模式被巧妙地命名为外观模式(Facade),之所以这么称呼,是因为它将一个或数个类的复杂的一切都隐藏在背后,只显露出一个干净美好的外观。外观模式我们下一章节再学习。