设计模式总结

  • 特点
    • 关注于整体最终的结构,通过继承(用于将类结合在一起)和组合(用于将对象结合在一起),构建出更大更加复杂的结构,进而提供更加强大的逻辑功能。
    • 分为类的结构模式和对象的结构模式。
      • 类的结构模式使用继承把类,接口等组合在一起,以形成更大的结构。类的结构模式是静态的。
      • 对象的结构模式描述怎样把各种不同类型的对象组合在一起,以实现新的功能的方法。对象的结构模式是动态的。
    • 所有的结构型设计模式在逻辑上都各自不同程度的隐含了“间接”“代理”“委托”的含义 ,有的明显,有的含蓄。
    • 所有的结构型模式的都离不开“分离,解耦”的概念,而“分离,解耦”之后,又通过某种形式建立联系,比如“组合”。
  • 种类
    • 门面/外观模式(Facade)(对象结构模式?)
      • 外观模式图效果图
      • 对调用者只暴露Façade类,Façade类不需要实现什么接口,提供封装了内部各类或组件或子系统的复杂操作
      • 对外提供一个统一的类作为调用众多内部类的入口,只提供有用的信息并隔离其他,facade类组合众多内部类
      • 特点主要是简化接口,以及减少客户端对外观组件的耦合。因为如果客户端变化来,组件的子系统变化了,不用影响客户端。除此之外,在封装组件时,适当的在外观类中添加一些自己想要的规则。如上面例子中各设备的开关顺序,或者拍照和打印之前其设备是否开启等。
      • 不使用该设计模式时:对于某个调用者来说,可能不需要使用众多内部类的那么多方法,但还要把用到的挑出来,比较麻烦。
      • 使用该设计模式时:针对某个调用者,只提供其关心和需要的功能,并且只需要接触这个facade即可,不用关心那么多内部类和逻辑。
      • 现实例子:
    • 适配器模式(对于单继承,通常是对象适配器)(Adapter)(类和对象结构模式都有)
      • 对象适配器(更常用)
        • 对象适配器模式类图
        • 对象适配器模式类图2
      • 类适配器(不常用,多继承耦合度高)
        • 使用多继承,通过集成被适配的类来获得他的功能
        • 类适配器模式类图
      • 对调用者暴露适配器Adapter的接口,适配器Adapter实现类中封装了被适配者Adaptee的不符合接口的操作
      • 和门面模式类似,但
        • 主要目的是对外提供标准接口(把一个接口转成另一个接口),而内部是组合了一些内部类的异构接口,适配器实现对外接口
        • 主要是对适配对象进行调整,以便适合消费者的需求。从而达到消费者和被适配者解耦的目的
        • 适配器和内部类没有直接联系即不用是实现统一接口
      • 不使用该设计模式时:由于对方的接口不够用或者说不符合需求结构,那么只能先调这些接口,然后自己再做转换等逻辑处理了。。这样就对修改开放了,因为修改了原有代码。
      • 使用该设计模式时:使用者直接使用适配器提供的接口,转换等逻辑放在适配器中处理,不用改调用者和被调用者的代码。
      • 现实例子:Type-C至3.5mm的耳机转接头
    • 代理模式(结构模式)(Proxy)(类结构模式)
      • 代理模式类图
      • 和适配器模式有一点点像,但是目的是控制访问,而不是适配接口,因此代理和原对象都实现了同一个对外接口
      • 现实例子:男同学A委托B给女生C送礼物,那么B就是代理,A和B都要会送礼物
      • 应用例子:远程代理、虚拟代理、安全代理、智能指引
    • 装饰器模式(Decorator)(类结构模式)
      • 装饰器模式类图
      • 对调用者暴露的都是同样的接口方法,只是这个方法的行为可以被不断的嵌套的包装/修改/增加行为
      • Decorator既继承自被装饰者接口,也组合拥有一个被装饰者的成员变量。
      • Decorator和被装饰者很像,不同点是被装饰者是基础,不像Decorator那样还可以再装饰别人
      • 被装饰者ConcreteComponent是基础,可以有多个,有不同的基础功能。
      • 装饰器模式例子
      • 通过在装饰器的构造函数中传入被装饰者,为其增加行为的同时保留原有行为,获得一个有新功能的新对象(同时保持原有的行为)
      • 本质是扩展,我们想要扩展一些功能,但是不想用继承
      • 定义:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
      • 意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
      • 主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
      • 何时使用:在不想增加很多子类的情况下扩展类。
      • 如何解决:将具体功能职责划分,同时继承装饰者模式
      • 优点
        • 装饰这模式和继承的目的都是扩展对象的功能,但装饰者模式比继承更灵活
        • 通过使用不同的具体装饰类以及这些类的排列组合,设计师可以创造出很多不同行为的组合
        • 装饰者模式有很好地可扩展性
      • 缺点
        • 装饰者模式会导致设计中出现许多小对象,如果过度使用,会让程序变的更复杂。并且更多的对象会是的查错变得困难,特别是这些对象看上去都很像。
    • 桥接模式(bridge)(类结构模式)
      • 桥接模式类图
      • 通常Abstraction和Implementor是两种分类方式,或者是两种角度、两种维度。Client在实际运作时,Abstraction和Implementor两个对象都需要,然后在Client中将他们组合起来一起使用。
      • 优势是可以任意组合!!!将抽象部分与它的实现部分分离,使它们都可以独立地变化。
      • 桥接模式不是将两个不相干的类链接,而是将一个需要多维度变化的类拆分成抽象部分和实现部分,并且在抽象层对两者做组合关联,是用组合的方式来解决继承的问题。
        • 桥接模式目的
        • 举例
          • 设想如果要绘制矩形、圆形、椭圆、正方形,我们至少需要4个形状类,但是如果绘制的图形需要具有不同的颜色,如红色、绿色、蓝色等,此时至少有如下两种设计方案
          • 第一种设计方案是为每一种形状都提供一套各种颜色的版本。
            • 第一种设计方案
          • 第二种设计方案是根据实际需要对形状和颜色进行组合,也就是桥接模式。
            • 第二种设计方案
      • 基于类的最小设计原则,通过使用封装、聚合及继承等行为让不同的类承担不同的职责。它的主要特点是把抽象(Abstraction)与行为实现(Implementation)分离开来,从而可以保持各部分的独立性以及应对他们的功能扩展。
      • 每一个Implementor都是对每一个RefinedAbstraction的一套行为的一套实现,也就是说把RefinedAbstraction的行为实现提出来了
      • 重点是,RefinedAbstraction相当于是要实现的目标且有多种,而Implementor相当于实现且每个都实现了所有的RefinedAbstraction
      • 本质上是实现了两组对象的动态两两组合,Abstraction实现类的操作函数中会调用/使用Implementation实现类的操作函数
        • RefinedAbstraction的操作函数中既有自己的逻辑,也使用了组合进来的Implementor的逻辑,即实现了动态组合
        • 从使用者的代码中就可以看出来:分别初始化两者各自的某一实例,然后通过构造函数把他们组合起来,然后再使用Abstraction的具体的操作函数
      • 适用场景
        • 不希望在抽象以及抽象的实现部分之间有一个固定的绑定关系。例如这种情况可能是因为,在程序运行时刻可以选择或切换实现部分;
        • 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充,使用Bridge模式可以对不同的抽象接口和实现部分进行组合,并分别对它们进行扩充。
        • 对一个抽象的实现部分的修改应该对用户不产生影响,即客户的代码不必重新编译。
      • 示例
        • 桥接模式示例1
        • 桥接模式示例2
    • 组合模式(composite)(类结构模式)
      • 主要是表达整体和部分的关系,并且对整体和部分对象的使用无差别。
      • 虽然整体和部分都继承自同一个抽象类/接口,但部分的增删子元素的方法只是个摆设,可能直接就烦会false了。
      • Composite模式将对象组合成树形结构以表示“整体-部分”的层次结构,其中的组合对象使得你可以组合基元对象以及其他的组合对象,从而形成任意复杂的结构。 Composite模式使得用户对单个对象和组合对象的使用具有一致性。
      • 组合模式类图
      • composite_file
      • composite_department
    • 享元模式(flyweight)(类结构模式)
      • 享元模式类图
      • 目的是减少对象的数量。如果在一个系统中存在多个相同的对象,那么只需要共享一份对象的拷贝,而不必为每一次使用都创建新的对象。目的是提高系统性能。
      • 说到享元模式,第一个想到的应该就是池技术了,String常量池、数据库连接池、缓冲池等等都是享元模式的应用,所以说享元模式是池技术的重要实现方式。
  • 对比
    • 代理模式和装饰器模式
      • 使用代理模式,代理和真实对象之间的关系在编译时就已经确定了,而装饰器者能够在运行时递归的被构造.(代理模式会在代理类中创建真实处理类的一个实例,所以可以确定代理和真实对象的关系,而装饰器模式是将原始对象作为一个参数传给装饰器类)
      • 代理模式的目的是控制访问(可以不增加行为),装饰器的目的是可以多次包装增加行为
      • 因此代理模式在构造函数中会初始化一个被代理类的对象再提供可用的原有功能给外界;装饰器模式会在构造函数时传入原被装饰对象,然后增加新功能。
    • 组合模式和装饰器模式
      • 组合模式的目的是表达父子关系,而装饰器模式是为了可以通过无限封装ConcreteComponent来增加各种功能
      • Leaf和Composite、ConcreteComponent和Decorator都是实现同一接口,且后者都组合包含前者
      • 但Composite包含一组Leaf,而Decorator只包含一个ConcreteComponent。
      • 但Composite一般不会再有子类,而Decorator会有子类,各个子类有不同的附加行为。
原文地址:https://www.cnblogs.com/wyp1988/p/10875089.html