Headlike设计模式幕布笔记

  • Headlike设计模式一本老书了
  • csdn上阅读体验可能不是很好,可以去这里看看,全部笔记通读下来需要20分钟。
  • 一样的部分继承父类,改变的部分封装接口
    • 一样的部分一般指类属性,改变的部分一般指方法的实现部分,如方法名也变可以封装成多个接口
  • 创建型涉及到将对象实例化,将客户从所需实例化的对象中解耦
  • 行为型都涉及到类和对象如何交互及分配职责
  • 结构型可以让你把类或对象组合到更大的结构中。
  • 面对接口编程,不针对实现编程
    • #设计原则 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起, 封装变化
    • #设计原则 针对接口编程,而不是针对实现编程
    • 解决的问题:继承有牵一发动全身,代码在多个子类中重复(如用重写的话),运行时的行为不容易改变,很难知道类的全部行为(算法)等问题
    • 分离类中变化的部分(如行为),定义成一个接口
    • 为接口构造几个实现类
    • 在类中添加接口对象
    • 实现当构造对象时实例化接口
    • 即抽象类中加接口对象
    • 示例

    • 增加设定行为方法,可以动态实例化行为接口

    • #设计原则 多用组合,少用继承
    • 总结
      • 即在类中声明算法接口
      • 算法接口的实例化可以通过构造器写死,或者用方法进行动态改变算法接口的实例
      • 算法的实现是调用接口中的方法
      • 接口中的方法的实例是由实例化接口的类来完成的
      • 即类中只会使用 接口.方法 不知道接口是由什么来实例的
  • 策略模式 【strategy 行为型】
    • 即是面对接口编程
    • 策略模式定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户、
    • 缺点:当代码使用大量的具体类时会产生一些麻烦
  • 观察者模式 【Observer 行为型】
    • 解决的问题:实现被观察对象在改变时可以通知观察者,且观察者可以随意增加或退出,不影响被观察对象的功能。
    • 出版者+订阅者 =》主题+观察者

    • 定义:观察者模式定义了对象之间的一对多依赖(依赖主题告诉观察者状态何时改变了),这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新,观察者依赖主题

    • 松耦合:当两个对象松耦合时,它们依然可以交互,但是不太清楚彼此的细节。
    • #设计原则 为了交互对象之间的松耦合设计而努力
    • Java内置观察者模式,主题需要继承Observable抽象类,观察者需要实现Observer接口

      • 先调用setChanged()方法,标记状态已经改变的事实
      • 然后调用两种notifyObservers()方法中的一个来发送通知:notifyObservers()或notifyObservers(Object arg)
      • 观察者接收通知:update (Observable o,Object arg)
    • 实现
      • 主题
        • 需要继承主题抽象类(不需要再写noity|add|removeObservers)或实现主题接口(还需要再写noity|register|removeObservers,以及观察者列表)
        • registerObservr即将观察者添加到观察者列表
        • removeObservers即将观察者移出观察者列表
        • notifyObservers 即遍布观察者列表,并调用观察者的update()方法
        • 在调用notifyObservers()之前,用setChange()来表示状态已经更新
      • 观察者
        • 需要实现Observer接口
        • 构造方法里有addObserver方法
        • update方法里如有Observable 参数,即可以用拉的方式,获取数据
        • update方法通常有 display()方法
    • 总结
      • 在观察者模式中,会改变的是主题的状态,以及观察者的数目和类型,用这个模式,你可以改变依赖于主题状态的对象,却不必改变主题。
      • 主题和 观察者都使用接口,观察者利用主题的接口向主题注册,而主题利用观察者接口通知观察者。这样可以让两者之间动作正常,又同时具有 松耦合的优点。
  • 装饰者模式 【Decorator 结构型】
    • 解决的问题:当一个类有许多个继承类的时候,类数量爆炸,基类加入新功能并不适用于所有的子类
    • #设计原则 类应该对扩展开放,对修改关闭
    • 我们不可能对所有部分采用开放-关闭原则,会导致代码变得复杂,也没必要
    • 定义:装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案
    • 实现,装饰者和被装饰者接口都继承自同一超类,实现装饰者接口的装饰者实例中有一个超类对象用于被装饰

    • 继承抽象类是为了有正确的类型,而不是继承它的行为,行为来自装饰者和基础组件,或与其他装饰者之间的组合关系。
    • 在装饰者模式下,因为基类和装饰者类都继承自同一超类,所以只要改变超类引用的子类即可。

    • 缺点: 会导致代码变的复杂,另外如果客户依赖的具体某一类,则包装后会出错
  • 工厂模式 | 工厂方法模式 【Abstract Factory| Factory Method 创建型】
    • 1.简单工厂
      • 解决的问题:虽然我们已经有了接口,当在new时总是会实例化一个具体类。因此当有多个子类时,我们就需要判断是要实例哪个子类,然而用if - else 时,很明显不容易维护和更新

        • 实现
          • 去除代码里变化的部分,即选择要实例化类型,

          • 简单工厂不是真正的模式,是一个编程习惯

        • #设计原则 静态方法定义对象的缺点,不能通过继承来改变创建方法的行为
        • #设计原则 在设计模式中,所谓的 “实现一个接口” 并 “不一定” 表示 “写一个类,并利用implement关键词来实现某个Java接口”,“实现一个接口” 泛指 “实现某个超类型(可以是类或接口)的某个方法。
      • #设计原则 要依赖抽象,不要依赖具体类“依赖倒置原则”
        不能让高层组件依赖低层组件,而且,不管高层或低层组件,”两者“都应该依赖于抽象。
      • 依赖倒置前

      • 依赖倒置后

    • 2.工厂方法
      • 简单工厂的缺点:当有多个实体类继承,但每个实体类的实现方法不同时,需要将简单工厂里封装的方法,又还给子类去实现。
      • 所有工厂模式都用来封装对象的创建。工厂方法模式通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。

      • 定义: 工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类哪一个。工厂方法让类把实例化推迟到子类,用于减少父类的依赖。

      • 示例:工厂方法就是抽象方法。

      • 工厂方法是抽象的所以依赖子类来处理对象的创建,工厂方法必须返回一个产品,工厂方法将客户和实际创建具体产品的代码分隔开来,工厂方法可能需要参数来指定所需的产品。可以使用enum来规定参数
      • 工厂和简单工厂的区别:简单工厂里,工厂是一个creator使用的对象,在工厂里生产商品;工厂模式里,creator里有一个抽象的工厂方法(创建一个框架,让子类决定如何实现),由子类继承creator,每个子类具体实现工厂方法。
      • 当然工厂方法,也可以不是默认的,在子类里重写即可。
    • 3.抽象工厂
      • 解决问题:在工厂模式里,我们将类的实例化,用抽象工厂方法推迟到子类来实例,但在创建者子类中依然还是要判断要实例哪个产品子类。产品子类之间不同的部分,让抽象工厂来处理这种差异就可以了。使产品子类不用关心这些差异。将子类和这些差异解耦。
      • @注意 不用关心是指在构建类时不用关心,类在实例化时才具体写明要用到的工厂实例。详细可见示例
      • 示例:创建抽象工厂,以及工厂实例

      • 示例:工厂方法调用

      • 定义:抽象工厂模式提供一个接口,用于创建相关或依赖对象的家庭,而不需要明确指定具体类。

    • 工厂方法和抽象工厂的异同:
      • 都是负责创建对象
      • 工厂方法主要是通过继承让子类来创建对象,利用工厂方法需要扩展一个类,并覆盖工厂方法。用这种做法,客户只需要知道他们所需要的抽象类型就可以了,而由子类来负责决定具体类型。只负责将客户从具体类型中解耦。
      • 抽象工厂是通过对象的组合。提供一个用来创建一个产品家庭的抽象类型,这个类型的子类定义了产品被产生的方法。要使用这个工厂,必须先实例化它,然后将它传入一些针对抽象类型所写的代码中。所以同样可以将客户从具体类型中解耦。
      • 抽象工厂另一个优点是可以把一群相关的产品集合起来。
      • 抽象工厂经常会使用工厂方法来实现具体工厂。
      • 工厂方法总结

      • 抽象工厂总结

  • 单件模式 【Singleton 创建型】
    • 解决的问题:有一些对象其实我们只需要一个,比如说:线程池,缓存,注册表。创建多实例时会导致一些问题。全局(静态)对象的缺点,必须在程序一开始就创建好对象。
    • 定义:单件模式确保一个类只有一个实例,并提供一个全局访问点。
    • 经曲的单件模式示例(懒汉模式),将构造器声明为私有,然后用静态成员方法来调用这个私有构造器,添加一个静态成员变量来记录唯一实例。懒汉模式只有在需要这个实例时才会产生实例。缺点:在多线程下无法单例

    • 处理多线程:在getInstance()前加synchronized关键字,缺点:同步只是在第一次执行这方法时才真正需要,但每次同步会降低性能。
    • 解决synchronized缺点,要么忍受,要么使用“饥(饿)汉模式”,要么使用双重检查锁,
    • 饥(饿)汉模式示例,在静态初始化器中创建单件,能保证线程安全thread safe

    • “双重检查锁”减少使用同步,首先检查是否实例已经创建了,如果尚未创建,才进行同步

  • 命令模式 【Command 行为型】
    • 将方法封装调用
    • 解决的问题:当有多个不同的类的方法需要一个类去调用时,比如多功能遥控器,一个遥控器要控制多个设备。
    • 命令模式可以将“动作的请求者”从“动作的执行者”对象中解耦。
    • 定义:将“请求”封装成对象,以便使用不同的请求,队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
    • 顾客将订单交给服务员,服务员将订单给厨师,然后厨师完成订单,服务员和厨师是完全“解耦”的,服务员不需要知道是哪一个厨师做的。

    • 调用者将客户的命令对象储存,之后调用者通过调用命令对象的excute()方法来执行接收者的方法。命令对象中有接收者和接收者的方法

    • 使用命令对象,其他对象不知道究竟哪个接收者进行了哪些动作,只知道如果调用execute()方法,请求的目的就能达到。
    • 示例

    • 总体概念

    • #设计原则 当你不想返回一个有意义的对象时,空对象就很有用。客户也可以将处理Null的责任转移给空对象。比如遥控器不可能一出厂就有意义了,所以可以提供一一个空对象作为替代品。当调用方法时,这种方法可以什么都不做。
    • 当用命令对象实现撤销操作时,可以在命令对象中加undo()方法,如撤销前可能有多个状态,也可以加个属性用于记录之前的状态

    • 用命令对象用来一次执行多个命令,创建一个可以执行多个命令对象的命令对象,构造器参数为命令对象数组,即使用宏命令。

    • 命令对象可以运用在线程的工作队列中,每一个实现了命令接口的对象都被放进队列中。然后线程将从队列中取出一个命令,调用它的execute()方法,等待这个调用完成,然后将此命令对象丢弃,再取出下一命令
  • 适配器模式 【Adapter 结构型】
    • 解决问题:如是让A 适配 B,则意味着用B的子类去声明A类型。
    • 创建一个适配器类继承或实现A,即适配器成为A类子对象,且该适配器中有个B类的对象,在适配器类中实现所有A类的方法,方法体为B类的方法。
    • 让一个适配器包装多个适配者,涉及到外观模式
    • 定义:适配器模式将一个类的接口,转换成客户期望的另一个接口。适配器让原来接口不兼容的类可以合作无间。

    • #设计原则 使用对象组合,以修改的接口包装被适配者。
    • @注意 适配器分为“对象”适配器和“类”适配器,“类”适配器需要双重继承才能实现(继承被适配者和目标类)。“对象”适配器除了可以适配被适配者和目标类,而且还可以适配被适配者 的任何子类。
    • 与装饰者的区别,装饰者负责给被包装的类添加新方法,装饰者负责改变接口,即改变类型。
  • 外观模式 【Facade 结构型】
    • 解决的问题:当接口太多时,简化接口
    • 示例

    • 定义:外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。
    • #设计原则 最少知识原则(墨忒耳法则):只和你的密友谈话。不要调用方法返回对象的方法。
  • 模板方法模式 【Template Method 行为型】
    • 解决的问题:当有多个类中出现相似的方法时
    • 模板方法:用继承,让父类里面存有共同方法,将共同方法定义在父类里,将相似方法在父类里定义成抽象方法。
    • 模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现。模板方法构造函数定义成final以免子类改变算法顺序。

    • 模板方法模式:在一个方法中定义一个算法的骨架,而将一些叔延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

    • hook(): 默认不做事的方法,子类可以视情况决定要不要覆盖它们。钩子是一种被声明在抽象类中,但只有空的或者默认的实现。钩子可以让子类有能力对算法的不同点进行挂钩。要不要挂钩,由子类自行决定。钩子有好几种用途。
    • 钩子示例:钩子作为条件控制,父类里根据钩子的返回值运行算法,钩子默认为true. 在子类中可以重写钩子,来返回真或假。

    • 钩子示例二:是让子类有机会对模板方法中的某些即将发生的步骤作出反应。比如说。名为justReOrderedList()的钩子方法允许子类在内部列表重新组织后执行某些动作。
    • 什么时候用抽象方法,什么时候用钩子
      • 当子类“必须”实现某个步骤方法时用抽象方法,如果是这个部分是可选的则用钩子
    • #设计原则 好莱坞原则:别调用(打电话给)我们,我们会调用(打电话给)你。
    • 在好莱坞原则下,我们允许低层组件将自己挂钩到系统上,但是高层组件会决定什么时候和怎样使用这些低层组件。 换句话说,高层组件对低层组件方式是 “别调用我们,我们会调用你"
    • 模板方法下的好莱坞原则

    • #设计原则 依赖倒置原则让我们尽量避免使用具体类,多用抽象类。而好莱坞原则是用在创建框架或组件上的一种技巧,好让低层组件能够被挂钩进计算中,而且又不会让高层组件依赖低层组件,两者的目标都是在于解耦,但是依赖倒置原则更加注意如何在设计中避免依赖。
    • 和策略模式,和工厂方法的不同:
      • 策略模式定义一个算法家庭,并让这些算法可以互换,通过对象组合的方式进行算法实现。
      • 模板方法是定义一个算法大纲,而由子类来定义其中某些步骤的内容。在算法中的个别步骤可以有不同的实现细节,但是算法的结构依然维持不变。通过继承的方式进行算法实现。
      • 工厂方法是在父类中定义抽象方法,在子类中实现抽象方法决定要实现化哪个具体的产品类。
  • 迭代器模式 | 组合模式 【Iterator 行为型】【Composite 结构型】
    • 迭代器模式
      • 解决的问题:当把对象堆起来成为一个集合时,可以让客户遍历对象,又无法窥视你存储对象的方式
      • 当有多个不同的集合需要遍历时,可以封装遍历

      • 迭代器模式(外部):示例

      • java.util.Iterator示例

      • 定义:迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内容的表示。

      • 外部迭代器与内部迭代器的区别:客户调用next()取得下一个元素,而内部迭代器则是由迭代器自己控制。因为内部迭代器是自行在元素之间游走,所以你必须告诉迭代器在游走的过程中,要做些什么事情,也就是说,你必须将操作传入给迭代器。因为客户无法控制遍历的过程,所以内部迭代器比外部迭代器没有弹性。
      • #设计原则 单一责任:一个类应该只有一个引起变化的原因
      • #设计原则 高内聚指当一个模块或一个类被设计成只支持一组相关的 功能时,我们说它具有高内聚;反之,当被设计成支持一组不相关的功能时,我们说它具有低内聚。
      • @注意 map的iterator获取的是值的迭代器

      • 缺点:迭代器模式无法支持子菜单即菜单中的菜单。
      • 解决方法:用树形结构来管理菜单,并使迭代器可以有弹性地在菜单项之间游走。
    • 组合模式
      • 定义:组合模式允许你将对象组合成树形结构来表现"整体/部分"层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。用户调用组件,组件有组合和叶节点,组合里包含了组件(即树里节点和叶子,节点下又是一个树)

      • 实现:叶子菜单里存菜单名加具体菜名和价格,节点菜单里存菜单名和保存下一级各菜单的数组。

      • 组合迭代器,在菜单内添加一个创建迭代器方法。遍历组件内的菜单项。创建迭代器栈,如果遍历到菜单则向栈添加一个迭代器,如果遍历到菜单则返回该组件。迭代器判断是否有下一个hasNext,当迭代器遍历完当前层级时,则返回下一个迭代器。即先序遍历。

      • 空迭代器,菜单项里没什么可以遍历的,实现父类中的createIterator()就有两种选择。
        • 选择一:返回null, 我们可以让createIterator()方法返回null, 但是这么做的话,我们的客户代码就需要语句判断是否为null
        • 选择二:返回一个空迭代器,而这个迭代器的hasNext()永远返回false

      • #设计原则 保持透明性,组合内所有的对象都必须实现相同的接口,否则客户就必须操心哪个对象用哪个接口。
  • 状态模式 【State 行为型】
    • 基本常识:策略模式和状态模式是双胞胎,策略模式围绕可以互换的算法来创建业务。状态模式通过改变对象内部的状态来帮助对象控制自己的行为。
    • 要解决的问题:比如当给状态图编码时,为每一个状态的转变都写了方法,这时加了新需求,状态图又要改变你会发现又要改代码。这就不符合面对对象了。
    • 方案:定义一个State接口,状态图每个动作都有一个对应的方法,即每个状态都有对不同方法的响应情况。为每个状态实现状态类。最后将动作委托到状态类。

    • 示例:将每个状态的行为局化到自己的类中,将;将容易产生问题的if语句删除,以方便日后维护;对修改关闭,对扩展开放,因为可以加入新的状态类

    • 定义:状态模式允许对象(糖果机)在内部状态(State)改变时改变它的行为(返回糖或者拒绝),对象看起来好像修改了它的类(实际上是使用组合通过简单引用不同的状态类来造成类改变的假象)。


      和策略模式的类图一模一样​​
    • 策略模式与状态模式的区别:
      • 策略模式客户通常主动指定所要组合的策略对象是哪一个,通常只有一个最适合的策略对象。可以在运行时改变行为
      • 状态模式是不用放置许多我条件判断的替代方案,通过将行为包装进状态对象中,你可以通过简单地改变状态对象来改变context的行为。利用不同的状态对象,改变上下文对象的状态
    • 客户不会直接和状态交互。上下文实例(糖果机)之间可以共享状态对象,需要把每个状态都指定到静态的实例变量中。
  • 代理模式 【Proxy 结构型】
    • 解决的问题:控制和管理访问
    • RMI
      • 远程代理:用RMI实现

      • 步骤:
        • 一、制作远程接口
          • 扩展java.rmi.Remote接口
            public interface MyRemote extends Remote{}
          • 声明所有的方法都会抛出RemoteException
            import java.rmi.*;public interface MyRemote extends Remote{​​ public String sayHello() throws RemoteException;}​​
          • 确定变量和返回值是属于基本类型或者可序列化类型。(primitive Serializable)
            • 返回值将从服务器经过网络返回给客户,所以必须是Serializable的,才可以将变量和返回值打包并传送。
        • 二、制作远程实现
          • 实现远程接口
          • 扩展UnicastRemoteObject,为了要成为远程服务对象,你的对象需要某些“远程的”功能。最简单的方式是扩展java.rmi.server.UnicastRemoteObject,让超类帮你做这些工作。
            public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{
          • 设计一个不带变量的构造器,并声明RemoteException
            public MyRemoteImpl() throws RemoteException{}
          • 用RMI Registry注册此服务。
            • 要让该服务被远程客户调用。要将此服务实例化,然后放进RMI registry中。当注册这个实现对象时,RMI系统其实注册的是stub,因为这是客户真正需要的。注册服务使用了java.rmi.Naming类的静态rebind()方法。
              try{ MyRemote service=new MyRemoteImpl();Naming.rebind("RemoteHello",service);}cathc(Exception ex){...}​
        • 三、产生stub和skeleton
          • 在远程实现类上执行rmic
        • 四、执行remiregistry
          • 开启一个终端,启动remiregistry
        • 五、启动服务
          • 开启另一个终端,启动服务
        • 代码

        • 服务端

        • 客户端

    • 只需要在接口类上加extends Serializable,所有的子类就可以在网络上传递了,不像序列化的字段可以在前面加transient
    • 定义:代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问

    • 虚拟代理(virtual proxy)
      • 和远程代理的区别:
        • 远程代理可以作为另一个JVM上对象的本地代表。调用代理的方法,会被代理利用网络转发到远程执行,并且结果会通过网络返回给代理,再由代理将结果返回给用户

        • 虚拟代理作为开销大的对象的代表。虚拟代理经常直到真正需要一个对象的时候才创建它。由虚拟代理来扮演对象的替身。对象创建后,代理就会将请求直接委托给对象。

      • 类图

      • 示例

    • 保护代理(动态代理)Java API中的实现,java.lang.reflect

      • 代码不能直接放在proxy里因为proxy不是你直接实现的,要放在InvocationHandler中,它的作用是响应代理的任何调用,你可以把InvocationHandler想成是代理收到方法调用后,请求做实际工作的对象。
      • 步骤
        • 一、创建InvocationHandler

          • 实现InvocationHandler接口, 实现invoke()方法

        • 二、创建Proxy类并实例化Proxy对象
          • (被代理类名)Proxy.newProxyInstance(类对象.getClassLoader(),类对象.getInterfaces(),new InvocationHandler(被代理对象));

        • 三、测试配对服务

      • 动态代理是因为运行时才将它的类创建出来,代码开始执行时,还没有proxy类,它是根据需要从你传入的接口创建的。
    • 其它代理
      • 防火墙代理
      • 智能引用代理,进行额外动作
      • 缓存代理,允许多个用户共享结果,以减少计算或网络延迟
      • 同步代理,在多线程的情况下为主题提供安全的访问
      • 复杂隐藏代理,用来隐藏一个类的复杂集合的复杂度,并进行访问控制。
      • 写入时复制代理,用来控制对象的复制,方法是延迟对象的复制
  • 模式的携手合作
    • Quackable将抽象鸭子叫
    • 用适配器将鹅子适配成Quackable,现在可以调用鹅适配器的quack()方法让鹅叫
    • 计算呱呱叫的次数,使用装饰者模式,添加QuackCounter
    • 担心他们忘了加装饰者,使用抽象工厂模式创建鸭子,也可以创建鸭子适配器
    • 又是鸭子,又是鹅的,为了解决管理问题,需要使用组合模式,将许多quackable集结成一个群,这模式也允许群中有群,以便让呱呱叫来管理鸭子家族。在实现过程中使用了ArrayLIst中的迭代器,使用了迭代器模式。
    • 专家希望被告知任何呱呱声响。使用观察者模式,甚至可以当一整群的观察者。
    • 示例

    • @注意 不能为了使用模式而使用模式
    • 和复合模式的区别,复合模式是指一群械被结合起来使用,以解决一般性问题
  • 复合模式
    • 模式通常被一起使用,并被组合在同一个设计解决方案中。
    • 复合模式在一个解决方案中结合两个或多个模式,以解决一般或重复发生的问题。
    • 如MVC
  • 总结
    • 模式是在某情境(context)下,针对某问题的某种解决方案。
      • 情境就是应用某个模式的情况,这应该是会不断出现的情况
      • 问题就是你想在某情境下达到的目标,但也可以是某情境下的约束
      • 解决问题就是你所追求的:一个通用的设计,用来解决约束,达到目标。
    • 连连看

    • 模式分类

  • 桥接模式 【Bridge 结构型】
    • 不只改变你的实现,也改变你的抽象
    • 解决的问题:虽然已经将物体抽象出来了,但随着使用时间的增长,抽象也是会被改变
    • 类图,抽象和实现不是继承关系,而是依赖关系

    • 优点
      • 将实现予以解耦,让它和界面之间不再永久绑定
      • 抽象和实现可以独立扩展,不会影响到对方。
      • 对于“具体的抽象类”所做的改变,不会影响到客户
    • 用途和缺点
      • 适合使用在需要跨越多个平台的图形和窗口系统上
      • 需要不同的方式改变接口和实现时,你会发现桥接模式很好用
      • 增加了复杂度
  • 生成器模式(行为)【Builder 创建型】
    • 使用生成器模式封装一个产品的构造过程,并允许按步骤构造。
    • 解决的问题,创建复杂结构,且不和创建它的步骤混在一起。如产生不同的度假计划。
    • 类图:将规划的创建过程,封装到一个对象中,然后让客户调用生成器为它创建旅游规划

    • 优点
      • 将一个复杂对象的创建过程封装起来
      • 允许对象通过多个步骤来创建,并且可以改变过程(这和只有一个步骤的工厂模式不同)
      • 向客户隐藏产品内部的表现
      • 产品的实现可以被替换,因为客户只看到一个抽象的接口
    • 用途和缺点
      • 经常被用来创建组合结构
      • 与工厂模式相比,采用生成器模式创建对象的客户,需要具备更多的领域知识
  • 责任链模式 【Chain of Responsibility 行为型】
    • 处理的问题,将不同类型的邮件发送给不同的部门进行处理
    • 类图,创建一个对象链,每个对象依序检查此请求,并对其进行处理,或者将它传给链中的下一个对象。

    • 优点:
      • 将请求的发送者和接受者解耦
      • 可以简化你的对象,因为它不需要知道链的结构
      • 通过改变链内的成员或调动它们的次序,允许你动态地新增或者删除责任
    • 用途和缺点
      • 经常被使用在窗口系统中,处理鼠标和键盘之类的事件
      • 并不保证请求一定会被执行;如果没有任何对象处理它的话,它可能会落到链尾端之外
      • 可能不容易观察运行的特征,有碍于除错。
  • 轻量(蝇量,享元)模式 【Flyweight 结构型】
    • 解决的问题,当需要创建一个类的多个对象时,可能消耗过多不必要的资源。

    • 类图:只用一个树实例和一个客户对象来维护“所有”树的状态。这就是蝇量模式。

    • 优点:
      • 减少运行时对象实例的个数
      • 将许多“虚拟”对象的状态集中管理
    • 用途和缺点:
      • 当一个类有许多实例,而这些实例能同一方法控制的时候,我们就可以使用蝇量模式。
      • 一旦你实现了它,那么单个的逻辑实例将无法拥有独立而不同 的行为。
  • 解释器 【Interpreter 行为型】
    • 类图

  • 中介者模式 【Mediator 行为型】
    • 用来集中相关对象之间复杂的沟通和控制方式
    • 解决的问题:持续地追踪每个对象的每个规则,以及众多对象之间彼此错综复杂的关系,实在不容易。

    • 类图

    • 优点
      • 通过将对象彼此解耦,可以增加对象的复用性
      • 通过将控制逻辑集中,可以简化系统维护
      • 可以让对象之间传递的消息变得简单而且大幅减少。
    • 用途和缺点
      • 如果设计不当,中介者对象本身会变得过于复杂。
  • 备忘录模式 【Memento 行为型】
    • 解决的问题:储存进度
    • 类图:储存系统关键对象的重要状态,维护关键对象的封装

    • 优点:
      • 将被储存的状态放在外面,不要和关键对象混在一起,这可以帮助维护内聚。
      • 保持关键对象的数据封装。
      • 提供了容易袜的恢复能力。
    • 用途和缺点
      • 备忘录用于存在状态
      • 使用备忘录的缺点:储存和恢复状态的过程可能相当耗时
      • 在Java系统中,其实可以考虑使用序列化机制储存系统的状态。
  • 原型 【Prototype 创建型】
    • 创建给定类的实例的过程很昂贵或很复杂时,就使用原型模式
    • 类图,复制现有的实例来创建新的实例

    • 优点
      • 向客户隐藏制造新实例的复杂性
      • 提供让客户能够产生未知类型对照的选项
      • 在某些环境下,复制对象比创建新对象更有效。
    • 用途和缺点
      • 在一个复杂的类层次中,当系统必须从其中的许多类型创建新对象时,可以考虑原型。
      • 使用原型模式的缺点:对象的复制有时相当复杂。深复制和浅复制
  • 访问者 【Visitor 行为型】
    • 当你想要为一个对象的组合增加新的能力,且封装并不重要时,就使用访问者模式

    • 类图:访问者必须参观组合内的每个元素,这样的功能是在导游对象中,访问者通过导游的引导,收集组合中的所有对象的状态。一旦状态被收集了,客户就可以让访问者对状态进行各种操作。当需要新的功能时,只要加强访问者即可。

    • 优点
      • 允许你对组合结构加入新的操作,而无需改变结构本身
      • 想要加入新的操作,相对容易
      • 访问者所进行的操作,其代码是集中在一起的。
    • 用途和缺点
      • 当采用访问者模式的时候,就会打破组合类的封装。
      • 因为游走的功能牵涉其中,所以对组合结构的改变就更加困难
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值