• 适配器模式和外观模式


          适配器模式提供了将一种对象转换成另一种对象的能力,利用它可以实现两个不兼容接口的协调工作。外观模式是封装对象内的复杂逻辑,对外提供一个简化的接口。

    1. 适配器模式

          生活中最常见的适配器的使用场景就是各种转换线和转换插头,例如投影仪到电脑之间的转换线,港版iPhone和国内插座之间的转换插头等。下面就以iPhone和插座之间的转换插头为例来看看适配器模式的用法。

          港版iPhone使用的英式插头,如左图所示,这种插头没法直接插在国内的标准插座上,要使用类似右图的转换器才行,那么现在需要做的就是找到一个转换器(适配器),将英式插头转换成符合国内标准的插头,也就是将EnglishPlug转换成ChinesePlug。(注:下面两个图片来源:https://zhidao.baidu.com/question/1365859698524477699.html

                                          

           先看一下插头的定义:

    1 public interface EnglishPlug{
    2     void charge();  // 英式插头可以插到插座上充电  
    3 }
    4 
    5 public interface ChinesePlug{
    6     void charge();  // 中式插头也可以插到插座上充电  
    7 }

          接下来是英式iPhone插头和中式iPhone插头:

     1  public class EnglishiPhonePlug implements EnglishPlug{
     2      @Override
     3      public void charge(){
     4          System.out.println("英式插头在充电");
     5      }
     6  }
     7  
     8  public class ChineseiPhonePlug implements ChinesePlug{
     9      @Override
    10     public void charge(){
    11         System.out.println("中式插头在充电");
    12     }
    13 }

          由于两个插头都已经做好了,回炉重造肯定是不可能了,只能增加一个转换器PlugConverter,将EnglishPlug伪装成ChinesePlug,好让英式插头能在中式插座上充电。要伪装成ChinesePlug,就需要让PlugConverter实现ChinesePlug接口,在转换器中组合EnglishPlug来完成转换工作,代码如下:

     1 publich class IPhonePlugConverter implements ChinesePlug{
     2     private EnglishPlug englishPlug;
     3     
     4     public IPhonePlugConverter(EnglishPlug englishPlug){
     5         this.englishPlug = englishPlug;
     6     }
     7 
     8     @Override
     9     public void charge(){
    10         englishPlug.charge();
    11     }
    12 }

          现在需要写一个测试类来看看这个转换成到底能不能用:

    1 public static void main(String[] args){
    2     ChinesePlug chinesePlug = new IPhonePlugConverter(new EnglishiPhonePlug());
    3     chinesePlug.charge();  //输出:英式插头在充电
    4 }

          可以看到,我们成功的用EnglishPlug“冒充”了ChinesePlug,实现了转换器的功能。当然,上面介绍的只是讲一个接口转换成另一个接口,实际上可以将一个接口转换为多个其他接口。

    2. 外观模式

          外观模式提供了简化接口的能力,将内部复杂的实现封装起来,开放给外部一个简单的接口,从而降低使用的复杂性。

    以洗衣机为例,洗衣机有半自动和全自动两种,半自动洗衣机需要我们自己先注水,然后洗涤,放水,最后脱水,这几部需要我们手动一步一步完成,虽然可以做到精细化控制(例如可以自由选择注水多少,脱水几分钟),但是用起来不免有些麻烦,而全自动洗衣机只需要按下启动键就OK了,简单了许多。

          下面是半自动洗衣机的定义:

     1 public class SemiautoWashingMachine{
     2     public void addWater(){
     3         System.out.println("手动注水");
     4     }
     5 
     6     public void washing(){
     7         System.out.println("开始洗衣服");
     8     }
     9 
    10     public void drainage(){
    11         System.out.println("手动排水");
    12     }
    13 
    14     public void dehydration(){
    15         System.out.println("手动脱水");
    16     }
    17 }

          用户使用半自动洗衣机,需要一步一步分别调用addWater(),washing(), drainage(), dehydration()这些接口。

          全自动洗衣机定义如下:

     1 public class FullautoWashingMachine{
     2     public void addWater(){
     3         System.out.println("手动注水");
     4     }
     5 
     6     public void washing(){
     7         System.out.println("开始洗衣服");
     8     }
     9 
    10     public void drainage(){
    11         System.out.println("手动排水");
    12     }
    13 
    14     public void dehydration(){
    15         System.out.println("手动脱水");
    16     }
    17     
    18     //对外提供的简单接口
    19     public void simpleWashing(){
    20         this.addWater();
    21         this.washing();
    22         this.drainage();
    23         this.dehydration();
    24     }
    25 }

          用户使用全自动洗衣机,就只需要调用simyleWashing()就行了。

          从上面可以看出来, 外观模式并没有增加新的功能,只是将原来的一些操作封装到一个接口里面,对外提供了一个简单的接口,避免让用户解除到底层,让系统更加容易使用。当然,如果你愿意,对象原来的一些底层功能(addWater()等方法)你仍然可以自由使用,像半自动洗衣机那样,每一步都手动来操作,只不过这样一来,用户就与对象的底层细节耦合在一起了。

    3. 总结

          总的来说,适配器模式提供了讲一个接口转换成其他接口的能力,而无需修改原来的接口;外观模式提供简化接口的能力,让使用者与接口内部的细节解耦,符合“最小知道原则”。

    4. 参考

    <<Head First设计模式>>

  • 相关阅读:
    LOJ #2109. 「JLOI2015」骗我呢 数形结合+组合+容斥
    LOJ #2729. 「JOISC 2016 Day 1」俄罗斯套娃 扫描线+贪心
    LOJ #2508. 「AHOI / HNOI2018」游戏 拓扑排序
    LOJ #2106. 「JLOI2015」有意义的字符串 构造+矩阵乘法
    LOJ #2471. 「九省联考 2018」一双木棋 记忆化搜索
    python的md5和base64加密
    [转]python的find()方法
    [转]python的startswith()方法
    获取http请求的响应状态
    with...as...用法
  • 原文地址:https://www.cnblogs.com/NaLanZiYi-LinEr/p/11518193.html
Copyright © 2020-2023  润新知