暮爱深秋 的笔记

人如果没有梦想,那跟咸鱼有什么区别呢?

2020-09-13 14:25

设计模式之结构型模式

暮爱深秋

其它

(777)

(0)

收藏

blog

结构型模式

结构型模式描述如何将类或者对象按照某种布局组成更大的结构。

一、代理模式

定义

由于某些原因需要给某对象提供一个代理以控制对该对象的访问。

访问对象不能或者不适合直接引用对象,代理对象作为访问对象与目标对象之间的中介。

优点与缺点

  • 优点

    1. 代理模式在客户端和目标对象中间起到一个中介作用和保护目标对象的作用。

    2. 代理对象可以扩展目标对象的功能。

    3. 代理模式能够将客户端与目标对象分离,在一定程度上降低了系统的耦合度。

  • 缺点

    1. 在客户端和目标对象中间加了一个代理对象,或造成请求速度减慢。

    2. 增加了系统的复杂度。

结构

  • 静态代理

  1. 抽象主题类(Subject):通过接口或者抽象类声明真实主体和代理对象实现的业务方法。

    interface Subject{    void request();
    }
  2. 真实主题类(Real Subject):通过实现抽象主题中具体业务,是代理对象所代表的真实对象,是最终要引用的对象。

    class RealSubject implements Subject{    @Override
        public void request(){
            System.out.println("访问真实主题方法...");
        }
    }
  3. 代理类(Proxy):提供与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制和扩展真实主题的功能。

    class Proxy implements Subject{    private RealSubject realSubject;    
        @Override
        public void request(){        if (realSubject == null) {
                realSubject = new RealSubject();
            }
            preRequest();
            realSubject.request();
            afterRequest();
        }  
    
        public void preRequest(){
            System.out.println("访问真实主题之前的预处理......");
        }    public void afterRequest(){
            System.out.println("访问真实主题之后的后续处理......");
        } 
    }
  • JDK动态代理 抽象主题类与真实主题类同上。
    代理类不需要实现接口

    public class DynamicProxy {    // 定义一个目标对象
        private Object target;    public DynamicProxy(Object target){        this.target = target;
        }    // 传统方法
        public Object getProxyInstance(){        return Proxy.newProxyInstance(
                    target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(),                new InvocationHandler() {                    @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            preRequest();
                            Object returnValue = method.invoke(target, args);
                            afterRequest();                        return  returnValue;
                        }
                    }
            );
        }    // lambda表达是
        public Object getProxyInstanceLambda(){        return Proxy.newProxyInstance(
                    target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(),
                    (proxy, method, args) -> {
                        preRequest();
                        Object returnValue = method.invoke(target, args);
                        afterRequest();                    return  returnValue;
                    }
            );
        }    private void preRequest(){
            System.out.println("动态代理访问真实主题方法之前的预处理.......");
        }    private void afterRequest(){
            System.out.println("动态代理访问真实主题之后的后续处理......");
        }
    }

二、适配器模式(Adapter)

定义

将一个类的接口转换成客户需要的接口,使得原本不兼容的而不能一起工作的那些类能够一起工作。

优点与缺点

优点:

  1. 客户端通过适配器可以透明的调用目标接口。

  2. 复用了现有的类,程序员不需要修改原有的代码而重用现有的适配器类。

  3. 将目标类与适配器类解耦,解决了目标类和适配者类接口不一致的问题。

缺点

  • 对于适配器来说,更换适配器的实现过程比较复杂。

结构与实现

  1. 目标接口(Target):当前系统业务所期待的接口。

  public interface CommonInterface {  
      public void ListenMusicByCommonHeadset();
  }
  1. 适配者类(Adaptee):被访问和适配的现存组件库中的组件接口。

  public class TypeCPhone {  
      public void listenMusic(){
          System.out.println("用type-c接口的耳机听音乐......");
      }
  }
  1. 适配器类(Adapter):转化器,将适配者类转换成目标接口,让客户目标接口的格式访问适配者。

  • 类适配器(不推荐,慎用继承)

  public class ClassAdapter extends TypeCPhone implements CommonInterface {      @Override
      public void ListenMusicByCommonHeadset() {
          System.out.println("借助Type-c转3.5mm接口的适配器听歌");          this.listenMusic();
      }
  }
  • 对象适配器(推荐)

  public class ObjectAdapter implements CommonInterface {  
      private TypeCPhone phone;  
      public ObjectAdapter(TypeCPhone phone){          this.phone = phone;
      }  
      @Override
      public void ListenMusicByCommonHeadset() {
          System.out.println("借助Type-c转3.5mm接口的适配器听歌");
          phone.listenMusic();
      }
  }

三、桥接模式(Bridge)

定义

将抽象与实现分离,使其可以独立变化。用组合关系来代替继承来实现,从而降低了抽象和实现这两个可变维度的耦合度。

优点与缺点

优点:

  • 由于抽象与实现相分离,所以扩展性比较强。

  • 其实现细节对客户透明。 缺点:

  • 由于聚合关系建立在抽象层,要求开发者对抽象层进行设计和编程,增加了系统的设计和理解难度。

结构与实现

  1. 抽象化角色(Abstraction):定义抽象类,并包含一个对实现化对象的引用。

 public abstract class Abstraction { 
     // 子类需要继承,所以是protected
     protected Implementor implementor; 
     public Abstraction(Implementor implementor){         this.implementor = implementor;
     } 
     abstract void doThings();
 
 }
  1. 扩展抽象化角色(Refined Abstraction):抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。

  public class RefinedAbstraction extends Abstraction {      public RefinedAbstraction(Implementor implementor) {          super(implementor);
      }  
      @Override
      void doThings() {
          System.out.println("具体实现化角色");
          implementor.doSomething();
      }
  }
  1. 实现化角色(Implementor):定义实现化角色的接口,供扩展实现化角色调用。

   public interface Implementor {      
          public void doSomething();
      }
  1. 具体实现化角色(Concrete Implementor):给出实现化角色接口的具体实现。

  public class ConcreteImplementor implements Implementor {          @Override
          public void doSomething() {
              System.out.println("扩展抽象化角色");
          }
      }

四、装饰模式(Decorator)

定义

在不改变现有对象结构的情况下,动态的给对象增加一些职责的模式。它属于对象结构型模式。

优点和缺点

优点:

  • 采用装饰模式扩展对象的功能比采用继承方式更加灵活。

  • 可以设计出多个不同的具体装饰类,创造出多个不同行为的组合。 缺点:

  • 装饰模式增加了很多子类,如果过度使用会使程序变得很复杂。

结构与应用

  1. 抽象构件(Component):定义一个抽象接口以规范准备接收附加责任的对象。

  public interface Component {      public void doSomething();
  }
  1. 具体构件(Concrete Component):实现抽象构建,通过装饰角色为其添加一些职责。

  public class ConcreteComponent implements Component {      @Override
      public void doSomething() {
          System.out.println("具体构件的方法");
      }
  }
  1. 抽象装饰角色(Decorator):继承抽象构建,并包含具体构建的实例。可以通过其子类扩展构件的功能。

  public abstract class Decorator implements Component {      private Component component;  
      public Decorator(Component component){          this.component = component;
      }  
      @Override
      public void doSomething() {
          component.doSomething();
      }
  }
  1. 具体装饰角色(Concrete Decorator):实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

  public class ConcreteDecorator extends Decorator {      public ConcreteDecorator(Component component) {          super(component);
      }  
      @Override
      public void doSomething() {          super.doSomething();
          addFunction();
      }  
      private void addFunction() {
          System.out.println("附加功能!");
      }
  }

五、外观模式(Facade)

定义

通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易访问的模式。该模式对外有一个统一的接口, 外部应用程序不用关心内部子系统的具体细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。

优点与缺点

优点:

  1. 降低了子系统与客户端之间的耦合度,是的子系统的变化不会影响调用它的客户类。

  2. 对客户屏蔽了子系统组件,减少了客户处理的对象数目,并使得子系统使用起来更加容易。

  3. 降低了大型软件系统中的编译依赖性,简化了系统在不同平台之间的移植过程。

缺点:

  1. 不能很好的限制客户使用子系统类。

  2. 增加新的子系统可能需要修改外观类或客户端的源代码,违反了开闭原则。

结构与应用

  1. 外观角色(Facade):为多个子系统提供一个统一的接口。

  public class Facade {      private SubSystemA systemA;      private SubSystemB systemB;      private SubSystemC systemC;  
      public Facade(){
          systemA = new SubSystemA();
          systemB = new SubSystemB();
          systemC = new SubSystemC();
      }  
      public void methodA(){
          systemA.doSomethingA();
      }  
      public void methodB(){
          systemB.doSomethingB();
      }  
      public void methodC(){
          systemC.doSomethingC();
      }
  }
  1. 子系统角色(Sub System):实现系统的部分功能,客户可以通过外观角色访问它。

  class SubSystemA {  
      public void doSomethingA(){
          System.out.println("子系统方法A");
      }
  }  class SubSystemB {  
      public void doSomethingB(){
          System.out.println("子系统方法B");
      }
  }  class SubSystemC {  
      public void doSomethingC(){
          System.out.println("子系统方法C");
      }
  }
  1. 客户角色(Client):通过一个外观角色访问各个子系统的功能。

  public class App {  
      @Test
      public void testMethod(){
          Facade facade = new Facade();
          facade.methodA();
          facade.methodB();
          facade.methodC();
      }
  }

六、享元模式(Flyweight)

定义

运用共享技术来有效的支持大量细粒度对象的复用。通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免 大量相似类的开销,从而提高系统资源的利用率。

优点与缺点

优点:

  • 相同对象只要保存一份,这降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力。 缺点:

  1. 为了使对象可以共享,需要将一些不能共享的状态外部化,增加了程序的复杂度。

  2. 读取享元模式的外部状态会使得运行时间稍微变长。

结构与实现

状态

  1. 内部状态:不会随着环境改变而改变的可共享部分。

  2. 外部状态:指随环境改变而不可共享的部分。 结构

  3. 抽象享元角色(Flyweight):所有具体享元类的基类,为具体享元规范需要实现的公共接口,非享元外部状态以参数形式通过方法传入。

   public interface Flyweight {       void doSomething(UnsharableFlyweight unsharableFlyweight);
   }
  1. 具体享元角色(Concrete Flyweight):实现抽象享元角色中所规定的接口。

   public class ConcreteFlyweight implements Flyweight {   
       private String key;   
       public ConcreteFlyweight(String key) {           this.key = key;
       }   
       @Override
       public void doSomething(UnsharableFlyweight unsharableFlyweight) {
           System.out.println("具体享元");
           System.out.println("非享元信息是:"+unsharableFlyweight.getInfo());
       }
   }
  1. 非享元角色(Unsharable Flyweight):使不可共享的外部状态,以参数的形式注入具体享元角色中。

   public class UnsharableFlyweight {       private String info;       public UnsharableFlyweight(String info){           this.info = info;
       }   
       public String getInfo(){           return info;
       }   
       public void setInfo(){           this.info = info;
       }
   }
  1. 享元工厂角色(Flyweight Factory):负责创建和管理享元角色。

   public class FlyweightFactory {   
       private Map flyweightMap = new HashMap<>();   
       public Flyweight getFlyweight(String key) {
           Flyweight flyweight = flyweightMap.get(key);           if (flyweight != null) {
               System.out.println("具体享元对象"+key+"已经存在");
           }else{
               flyweight = new ConcreteFlyweight(key);
               flyweightMap.put(key, flyweight);
           }   
           return flyweight;
       }
   }

七、组合模式(Composite)

定义

将对象组合成树状层次的结构,用来表示部分及整体的关系,使用户对单个对象以及组合对象具有一致的访问性。

优点与缺点

优点:

  1. 组合模式可以使客户端可以一致的访问单个对象和组合对象,无需关系自己处理的使单个对象还是组合对象。简化了客户端代码。

  2. 更容易在组合体内加入新的对象,客户端不会因为加入新的对象而改变代码,满足开闭原则。 缺点:

  3. 设计较为复杂,客户端需要更多的时间清理类之间的关系。

  4. 不容易限制容器内的构件。

  5. 不容易用继承的方法来增加构件的新功能。

结构与实现

  1. 抽象构件(Component):为树叶构件和树枝构件声明公共接口,并实现他们的默认行为。在透明式的组合模式中抽象构件 还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作有树枝构件完成。

public interface Component {    public void add(Component component);    public void remove(Component component);    public Component getChild(int i);    public void operate();
}
  1. 树叶构件角色(Leaf):组合中的叶节点对象,没有子节点,用于实现抽象构件角色中生命的公共接口。

public class Leaf implements Component {    private String name;    public Leaf(String name) {        this.name = name;
    }    @Override
    public void add(Component component) {}    @Override
    public void remove(Component component) {}    @Override
    public Component getChild(int i) {        return null;
    }    @Override
    public void operate() {
        System.out.println("树叶"+name+"被访问");
    }
}
  1. 树枝构件对象(Composite):组合中的分支节点对象,有子节点。实现了抽象构件角色中声明的接口,主要作用是 存储和管理子部件,通常包含add(), remove(), getChild()等方法。

public class Composite implements Component {    private List children = new ArrayList<>();    @Override
    public void add(Component component) {
        children.add(component);
    }    @Override
    public void remove(Component component) {
        children.remove(component);
    }    @Override
    public Component getChild(int i) {        return children.get(i);
    }    @Override
    public void operate() {        for (Component component : children) {
            component.operate();
        }
    }
}


0条评论

点击登录参与评论