zoukankan      html  css  js  c++  java
  • 设计模式 —— 结构型模式

    结构型模式(Structural Pattern)关注如何将现有类或对象组织在一起形成更加强大的结构
    可分为两种:

    1. 类结构型模式:关心类的组合,由多个类可以组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关系
    2. 对象结构型模式:关心类与对象的组合,通过关联关系使得在一个类中定义另一个类的实例对象,然后通过该对象调用其方法。更符合“合成复用原则”

    1. 适配器模式(Adapter pattern)

    1.1 定义

    "Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces."
    将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作

    又称包装器(Wrapper),既可以作为类结构型模式,也可以作为对象结构型模式。

    使用前提或场景:解决两个已有接口间不兼容问题。Client面向接口编程,而该面向的接口又与第三方接口不兼容,两者又不便于修改,则可用Adapter协调工作

    个人理解:不能说是"转换",而是协调不兼容接口间工作。比如客户端期望调用的方法传参是一个样子(面向接口编程,该方法可上升为目标抽象类,下述角色中有提到),而现有第三方实现的满足业务功能的接口可用,但规定的参数格式不一样。但两者(目标抽象类与第三方接口)都不愿或者不能修改,因此,则需要一个适配器来协调两者工作。

    1.2 模式结构

    示例代码参考

    包含如下角色:

    1. Target(目标抽象类)
      客户期望的业务接口,可以是具体类,也可以是接口。

    2. Adapter(适配器类)
      适配器类可调用Adaptee接口,以对 Adaptee 和 Target 进行适配,使其协调工作。

    3. Adaptee(适配者类)
      被适配的角色,定义了可工作、已存在、待适配的接口,些情况下甚至没有源代码。

    4. Client(客户类)
      客户类面对目标抽象类进行编程

    可细分为两种模式:

    1. 类适配器模式:适配器类与适配者类是继承关系,因为Java不支持多重继承,因此该模式下目标抽象类只能是接口。
    2. 对象适配器:适配器类与适配者类是关联关系(也可以称为委派关系),即含有适配者类的成员变量

    1.3 模式扩展

    1. 缺省适配器模式(Default Adapter Pattern):当不需要实现接口提供的全部方法时,可先设计一个抽象类(缺省适配器)来实现该接口,并为每个方法提供一个默认实现(通常是空实现,也称钩子方法[Hook Method]),那么该抽象类的子类(具体业务类)可有选择的只覆盖父类中某些方法来实现需求。
    interface ServiceInterface{
    	void M1();
    	void M2();
    	void M3();
    }
    abstract class AbstractServiceClass implements ServiceInterface{
    	public void M1(){}
    	public void M2(){}
    	public void M3(){}
    }
    class ConcreteServiceClass extends AbstractServiceClass{
    	public void M2(){
    		System.out.println("具体业务方法");
    	}
    }
    
    1. 双向适配器:适配器中同时包含对目标类和适配者类的引用。

    1.4 优缺点

    也是其使用场景,可以在不修改客户、适配者、目标抽象类前提下,让几者兼容工作。同时适配器也能很方便的替换,符合开闭原则。

    2. 桥接模式(Bridge Pattern)

    2.1 定义

    "Decouple an abstraction from its implementation so that the two can vary independently."
    将抽象部分与它的实现部分解耦,使它们都能独立地变化

    又称柄体(Handle and Body)模式,接口(Interface)模式,属于对象结构型模式。

    使用场景:当一个类存在两个独立变化的维度时,为了减少因继承结构带来的具体类数量,可将变化的维度进行抽象化,再用关联方式将其联系起来。

    个人理解:如上面所讲,多变化维度如果用继承将会大大增加类的数量。比如下面例子中的"跨平台多格式播放器",若将其中一个维度用继承关系表达,再在其中定义另一个维度接口的成员变量,以此达到灵活组合的目的。

    2.2 模式结构

    1. Abstraction(抽象类)
      其中一个变化维度的继承关系结构中的抽象父类,一般来说 Implementor 接口仅提供基本操作,而 Abstraction 则可能会做更多更复杂的操作。其中定义了一个 Implementor 类型对象,并维护该对象,达成关联关系.

    2. RefinedAbstraction(扩充抽象类)

    3. Implementor(实现类接口)
      另一变化维度所抽象出来的接口

    4. ConcreteImplementor(具体实现类)

    2.3 优点

    1. 通过将另一维度抽象,并使用关联关系,一定程度上进行了解耦,也 满足了"合成复用原则",大大减少了因静态抽象继承结构可能带来的类的数量。

    2. 因为抽象,客户端面向两个维度抽象层编程,加上新增扩充抽象类或具体实现类均不需要修改其他任何代码,因此很好的符合了"依赖倒转原则"与"开闭原则"。

    3. 组合模式(Composite Pattern)

    3.1 定义

    "Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly."
    组合多个对象形成树形结构以表示"部分——整体"的层次结构。组合模式使客户能统一对待单个对象(即叶子对象)和组合对象(即容器对象)

    又称"部分-整体"(Part-Whole)模式,属于对象的结构模式

    使用场景:在具有整体(容器)和部分(叶子)的类层次结构中,希望能忽略两者的差异,使客户能一致对待它们。

    个人理解:通过定义一个抽象构件类,既能代表叶子也能代表容器构件,其中声明了构件的统一业务方法,该方法叶子与容器有不同的实现,但客户面向该抽象构件编程,因此可以统一处理而无须关心两者间差异。

    3.2 模式结构

    1. Component(抽象构件)
      可以是接口或者抽象类,声明叶子构件与容器构件共有业务方法

    2. Leaf(叶子构件)

    3. Composite(容器构件)
      在容器构件中,包含了一个集合用于储存子结点,该子结点可以是叶子、也可以是容器对象。且额外提供了管理子结点的方法,如addLeaf(Component com)等等

    4. Client(客户类)

    :该模式又可细分为:透明组合模式、安全组合模式

    • 透明组合模式:即将容器类中的额外方法(如addLeaf),提到抽象构件类中,使得所有构建类都有相同的接口,客户可透明的完全一致地对待所有对象。
      缺点很大:因为叶子对象和容器对象本质上是有区别,叶子对象不可能有成员对象。因此add等方法对叶子类是没有意义的,在运行时调用会出错。

    • 安全组合模式(推荐):即没有在抽象构件类中声明本该容器具有的方法,这是安全的。但这会造成客户不能完全针对抽象编程(因为add等方法是定义在容器类中的,只有声明为容器类型才能调用)无法一致使用叶子与容器构件。

    4. 装饰模式(Decorator Pattern)

    4.1 定义

    "Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality."
    动态地给一个对象添加职责。相较于继承,装饰模式则提供了一种更为灵活的方式来扩展功能。

    又称"油漆工模式"、"包装器(Wrapper)"(与适配器模式别名相同,但含义不同),是对象结构型模式。

    使用场景:无须使用继承,通过关联机制来动态、透明的为对象增加职责。

    个人理解:定义抽象构件(类或接口)声明业务方法,具体构件与装饰类均实现该接口。在装饰类中定义了构件类型的成员变量,在接口方法中调用该对象的方法并添加额外实现。而对客户来说是一直的,因为其面向抽象编程。
    该模式也能达到循环装饰,来添加功能。

    4.2 模式结构

    1. Component(抽象构件)
      声明了业务方法,客户端面向该抽象编程

    2. ConcreteComponent(具体构件)
      实现了抽象构件

    3. Decorator(抽象装饰类)
      (可选)实现抽象构件。当有多个装饰类时,可声明抽象装饰类,用以定义所有装饰类的统一行为,如维护一个抽象构件类型的引用。假如只有一个装饰类时,则可省略

    4. ConcreteDecorator(具体装饰类)
      内部调用被装饰对象方法,并额外增添新的功能。

    :该模式可细分为透明装饰模式与半透明装饰模式。

    • 透明装饰模式:即装饰类中未额外添加public方法,客户端可完全一致的使用具体构建类与装饰类。
    • 半透明装饰模式:装饰类中增添了自己的方法,意味着客户端必须声明为装饰类型才可调用,因此无法一致对待。

    4.3 优点

      一定程度上降低了静态继承带来的耦合度,符合”合成复用原则“,同时抽象层的定义也符合”开闭原则“,比如新增具体装饰类无须修改其他代码。

    5. 外观模式(Facade Pattern)

    5.1 定义

    "Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use."
    为子系统的一组接口提供一个统一的入口。外观模式定义了一个高层接口使得能更方便地使用子系统。

    又称门面模式,是对象结构型模式

    使用场景:若想简化客户端与复杂子系统间的操作,则可引入外观角色来为复杂子系统提供简化的入口

    个人理解:如上所述,客户端只需与外观角色交互,而由外观角色来整合调用子系统中的复杂接口

    5.2 模式结构

    1. SubSystem(子系统角色)
      每个子系统都可由客户端直接调用,也可以被外观角色调用。子系统并不知道外观角色的存在,对子系统而言,外观角色仅仅是另一个客户端而已

    2. Facade(外观角色)
      它将从客户端发来的请求委派到相应子系统

    5.3 优点

      如同使用情景一样,使用外观模式可为客户端提供很大方便,将客户端与子系统的内部复杂性分隔开,只需与外观角色交互即可。降低了客户与子系统耦合度,符合"迪米特法则"。

    6.享元模式

    TODO

    7. 代理模式(Proxy Pattern / Surrogate Pattern)

    7.1 定义

    "Provide a surrogate or placeholder for another object to control access to it."
    为某一对象提供一个代理,由代理对象来控制对原对象的引用

    属于对象结构型模式

    使用场景及个人理解:为现有对象的使用提供额外的控制,而无须修改现有类与客户调用,对客户端而言是透明的,无须关心具体实现,只需面向接口使用即可。Java中官方自带有对动态代理的支持。

    和“装饰模式”的不同:(1)代理中的引用是对真实主题角色的引用,而装饰模式中是对抽象主题角色的引用。(2)装饰模式的被装饰对象是由客户传入的,想额外增加修饰功能。而代理模式是内部创建被代理对象,且完全控制其行为。

    7.2 模式结构

    1. Subject(抽象主题角色)
      定义了业务方法,是真实主题与代理主题的共同接口

    2. Proxy(代理主题角色)
      内部包含对真实主题角色的引用,可完全控制真实主题的使用逻辑

    3. RealSubject(真实主题角色)

    7.3 扩展

    常见应用:

    1. 远程代理:远程代理可以将网络细节隐藏起来,使客户端不必考虑网络的存在。比如Java的RMI(Remote Method Invocation,远程方法调用),客户对象在客户端运行,想服务器端运行的远程对象发起请求。
    2. 虚拟代理:一种时间换空间的内存节省技术,将占用大量内存或处理复杂的对象推迟到使用它时才创建。比如Hibernate的懒加载

    Java中的动态代理,以及优缺点

    TODO:一个链接

  • 相关阅读:
    119. Pascal's Triangle II
    118. Pascal's Triangle
    112. Path Sum
    111. Minimum Depth of Binary Tree
    110. Balanced Binary Tree
    108. Convert Sorted Array to Binary Search Tree
    88. Merge Sorted Array
    83. Remove Duplicates from Sorted List
    70. Climbing Stairs
    陌陌面试经历
  • 原文地址:https://www.cnblogs.com/simpleito/p/10878865.html
Copyright © 2011-2022 走看看