zoukankan      html  css  js  c++  java
  • Head First 设计模式 --7 适配器模式 外观模式

    适配器模式:将一个类东街口转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。

    适配器模式有两种,对象适配器和类的适配器。先看一下对象适配器。

    还是看最开始鸭子的例子,如果此时鸭子不够了,需要一个火鸡来充当一个鸭子。

    对象适配器

    interface Duck {
      public void quack();
    
      public void fly();
    }
    
    interface Turkey {
      public void gobble();
    
      public void fly();
    }
    
    class WildTurkey implements Turkey {
      @Override
      public void gobble() {
        System.out.println("Gobble gobble");
      }
    
      @Override
      public void fly() {
        System.out.println("i am flying a short distance");
      }
    }
    
    class TurkeyAdaper implements Duck {
      Turkey turkey;
    
      public TurkeyAdaper(Turkey turkey) {
        this.turkey = turkey;
      }
    
      @Override
      public void quack() {
        turkey.gobble();
      }
    
      @Override
      public void fly() {
        for (int i = 0; i < 5; i++) {
          turkey.fly();
        }
      }
    }
    
    public class Test {
      public static void main(String[] args) {
        Turkey turkey = new WildTurkey();
        Duck turkeyAdaper = new TurkeyAdaper(turkey);
        turkey.gobble();
        turkey.fly();
    
        testDuck(turkeyAdaper);
      }
    
      static void testDuck(Duck duck) {
        duck.quack();
        duck.fly();
      }
    }

    类图:

    适配器的需要进行的工作和目标接口的大小成正比。如果一个目标接口很大,不用适配器的话,就要改写原来的代码来调用这个接口,这也会很耗费力气,相比之下,还是将所有的变化封装进一个适配类中比较好。

    假如上面还有还有一个鹅(Goose)也不够用了,还需要用火鸡来充当鹅,只需要将这个适配器在实现Goose的接口,这样这个适配器技能适配成Duck还能适配成Goose。

    然后看一下类的适配器

    interface Duck {
      public void quack();
    
      public void fly();
    }
    
    interface Turkey {
      public void gobble();
    
      public void fly();
    }
    
    class WildTurkey implements Turkey {
      @Override
      public void gobble() {
        System.out.println("Gobble gobble");
      }
    
      @Override
      public void fly() {
        System.out.println("i am flying a short distance");
      }
    }

    class AnotherTurkeyAdaper extends WildTurkey implements Duck { @Override public void quack() { } }

    类图:

    类的适配器继承原有类(WildTurkey),实现目标类(Duck)。这样适配器中可以具有目标类的方法,如果要扩招原有的类也可以覆盖重写原有类的方法。(自己感觉:这种模式的原有类的基类最好是一个抽象类,这样可以继承基类获取方法,而不是去实现基类的子类)

    就代码而言,两种模式的区别是对象适配器中需要持有原对象,而类的适配器是同时扩展两个类(实际上应该是同时继承两个类,但是java不允许多继承,只好实现目标接口),不需要在适配器持有原对象,如果需要可以重写原对象的方法。无论怎么做一定要扩展目标类(Duck),因为你就是想让不是目标类(Duck)的类型可以伪装成一个目标类(Duck)。

    对象适配器利用组合,可以扩展这个类的子类。类适配器利用继承,不需要重新实现整个被适配者,必要的时候,可以重写。对象适配器是利用组合,需要持有被适配者,这样可以将工作委托给适配者进行,更有弹性,同时也用到了组合优于继承。但是这是有代价的,需要在代码中在创建一个被适配者,代码量增加,而类适配器只需要这个适配器就可以,效率高。

    外观模式:提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

    利用了新的原则:最少知识原则(迪米特法则,不要和陌生人说话),定义类和类之间的松耦合

    首先先理解一下这个原则。(下面代码copy自 http://www.cnblogs.com/yucongblog/p/4620607.html   )
    下面这段代码严重违反迪米特法则:

    public class Teacher { 
        public void commond(GroupLeader groupLeader) {
            List<Girl> listGirls = new ArrayList<Girl>();
            for (int i = 0; i < 20; i++) {
                listGirls.add(new Girl());
            }
            groupLeader.countGirls(listGirls);
        }
    }

    我们在代码中这么写可能很常见,以后应该在写代码的时候应该想想这方面的问题。
    为什么违反了迪米特法则,在commend方法中,用到了Girl类,而Teacher类的行为commend在运行前Teacher类居然不知道还依赖了这个类。
    正确的做法:

    public class Teacher {
        public void commond(GroupLeader groupLeader) {
            groupLeader.countGirls();
        }
    }
    public class GroupLeader {
        private List<Girl> listGirls;
      
        public GroupLeader(List<Girl> _listGirls) {
            this.listGirls = _listGirls;
        }
        public void countGirls() {
            System.out.println("女生数量是:" + listGirls.size());
        }
    }

    迪米特法则希望,类中public尽量少,尽量多的private,protected,final。一定要减少类之间的耦合

    这个原则提供了一些方针:在对象的方法内,我们只能调用一下范围的方法
    1、该对想本身
    2、被当做方法的参数传进来的对象
    3、此方法所创建或实例化的任何对象  (前三点隐藏着一个注意的地方:如果某对象是调用其他方法的返回结果,不要调用改对象的方法)
    4、对象的组件

    外观模式代码:

    public class Test2Facade {
      public static void main(String[] args) {
        Facade facade = new Facade(new FacedeA(), new FacedeB(), new FacedeC());
        facade.method();
      }
    }
    
    class FacedeA {
      public void facadeA() {
    
      }
    }
    
    class FacedeB {
      public void facadeB() {
    
      }
    }
    
    class FacedeC {
      public void facadeC() {
    
      }
    }
    
    class Facade {
      private FacedeA facedeA;
      private FacedeB facedeB;
      private FacedeC facedeC;
    
      public Facade(FacedeA facedeA, FacedeB facedeB, FacedeC facedeC) {
        this.facedeA = facedeA;
        this.facedeB = facedeB;
        this.facedeC = facedeC;
      }
    
      public void method() {
        facedeA.facadeA();
        facedeB.facadeB();
        facedeC.facadeC();
      }
    }

    就是将一个大方法组成了一个小方法供client去调用。类图也不用了,基本上写代码的时候都是这么写的。要注意的就是尽量使用迪米特法则来设计外观模式。

  • 相关阅读:
    arcgis api 3.x for js 入门开发系列八聚合效果(附源码下载)
    arcgis api 3.x for js 入门开发系列七图层控制(附源码下载)
    arcgis api 3.x for js 入门开发系列六地图分屏对比(附源码下载)
    arcgis api 3.x for js 入门开发系列五地图态势标绘(附源码下载)
    arcgis api 3.x for js 入门开发系列四地图查询(附源码下载)
    Java里面获取当前服务器的IP地址
    Flutter at Google I/O 2018
    Modbus RTU 协议使用汇总
    plsql 创建表空间、用户、赋予权限
    Oracle:ODP.NET Managed 小试牛刀
  • 原文地址:https://www.cnblogs.com/badboyf/p/6212815.html
Copyright © 2011-2022 走看看