Loading

设计模式总结:创建型模式

创建型模式

  • 类模式
    • 工厂方法模式
  • 对象模式
    • 抽象工厂模式
    • 建造者模式
    • 原型模式
    • 单例模式
  1. 单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。
  2. 原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。
  3. 工厂方法(FactoryMethod)模式:定义一个用于创建产品的接口,由子类决定生产什么产品。
  4. 抽象工厂(AbstractFactory)模式:提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。
  5. 建造者(Builder)模式:将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。

1 简单工厂模式 Simple Factory

image-20210623151455241

1.1 定义

  • 简单工厂模式(Simple Factory Pattern),又称为静态工厂方法(Static Factory Method)模式
  • 根据参数的不同返回不同类的实例
  • 专门定义一个类来负责创建其他类的实例,被创建的实例通常具有共同的父类

包含如下角色

  • Factory 工厂角色
  • Product 抽象产品角色
  • ConcreteProduct 具体产品角色

1.2 模式分析

  • 对象的创建对象本身业务处理分离可以降低系统的耦合度 ,使得两者修改起来都相对容易。

  • 简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。

  • 优点

    • 实现了对责任的分割,提供专门的工厂类用于创建对象
    • 客户端无需知道所创建的具体产品类目,只需要知道产品类对应的参数即可
    • 引入配置文件,可以在不修改客户端代码的情况下更换和新增新的具体产品类
  • 缺点

    • 工厂类集合了所有产品创建逻辑,一旦不能工作,整个系统都会被影响
    • 会增加类的个数
    • 拓展困难,一旦添加新产品,就不得不修改工厂逻辑(违背了开闭原则)
  • 适用

    • 工厂类负责创建的对象比较少(不会导致工厂的逻辑太复杂)
    • 客户端只知道传入工厂类的参数,对于如何创建对象不关心
  • 简化

    • 可以把静态工厂方法写到抽象产品类中

      image-20210623154138187

1.3 例子

  • 根据不同的权限等级创建不同的用户对象,不同的用户对象拥有不同的操作权限

    image-20210623153554085

  • JDK日期格式化类

    image-20210623154017832

  • JDK加密技术

    image-20210623154029743

2 工厂方法模式 Factory Method

image-20210623154408591

2.1 模式动机

考虑简单工厂的不足,即要增加新产品时,除了增加一个新的具体产品类之外,还需要修改工厂类的代码,这就使得整个设计在一定程度上违反了“开闭原则 ”

修改:不再设计一个工厂类来统一负责所有产品的创建,而是将具体类的创建过程交给专门的工厂子类去完成

2.2 定义

  • 工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式

2.3 模式分析

  • 在工厂方法模式中,核心的工厂类不再负责所有产 品的创建,而是将具体创建工作交给子类去做。因此,工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品(符合开闭原则)

  • 在定义工厂和产品时都必须使用抽象层,如果需要更换产品类,只需要更换对应的工厂即可,其他代 码不需要进行任何修改。

    image-20210623154841377

  • 优点

    • 用户只需关心所需产品对应的工厂,无需关心创建细节,甚至无需知道具体产品类名
    • 工厂可以自主确定如何创建何种产品对象,如何创建对象的细节完全封装在工厂内部
    • 引入新产品时,无需修改抽象工厂和产品,无需修改客户端,也无需修改其他具体工厂和产品,只需要添加一个具体产品和工厂类即可
  • 缺点

    • 引入新产品时,需要引入具体工厂类,一定程度上增加了系统的复杂度
    • 客户端中需要使用对抽象层的定义,增加系统的抽象性和理解难度,需要用到反射等技术
  • 适用

    • 一个类不知道它所需要的对象的类
    • 一个类通过其子类来指定创建哪个对象
    • 将创建对象的任务委托给多个工厂子类中的一个,在使用时动态指定

2.4 例子

image-20210623154929931

3 抽象工厂模式 Abstract Factory

image-20210623155951981

3.1 模式动机

  • 工厂方法中,一个具体工厂对应一种具体产品
  • 有时候我们为需要一个工厂可以提供多个产品对象,而不是单一的产品对象

3.2 定义

  • 抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式

引入两个概念

  • 产品等级结构:即产品的继承结构,如抽象电视机是父类,具体品牌的电视机是其子类
  • 产品族:指由同一个工厂生产的,位于不同产品等级结构中的一组产品

包含以下角色:

  • AbstractFactory
  • ConcreteFactory
  • AbstractProduct
  • Product

3.3 模式分析

  • 优点

    • 隔离了具体类的生成,使得客户端不需要知道什么被创建
    • 所有的具体工厂都实现了抽象工厂中的公共接口,只需要替换具体工厂,就可以改变整个软件系统的行为
    • 高内聚、低耦合
    • 保证客户端始终使用同一个产品族的对象
    • 增加新的具体工厂和产品族很方便,无需修改已有系统(开闭原则)
  • 缺点

    • 添加新的产品时,很难扩展抽象工厂来生成新的产品
    • 新增新的产品族和工厂容易,新增新的产品等级结构难。即开闭原则的倾斜性
  • 适用

    • 一个系统不应当依赖产品类实例如何被创建、组合和表达的细节(对所有工厂模式都很重要)
    • 系统中有多个产品族,且每次只用一个
    • 属于同一个产品族的产品将在一起使用
    • 系统提供一个产品族的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现

3.4 例子

  • 一个电器工厂可以生产多个类型的电器,有多个工厂

    image-20210623160133960

  • 针对不同的数据库,提供Connector和Statement

    image-20210623160228470

4 工厂模式退化

image-20210623160840317

5 建造者模式 Builder

建造者模式(Bulider模式)详解 (biancheng.net)

image-20210623161621431

5.1 模式动机

  • 存在一些复杂的对象,有多个组成部分,如汽车包括轮胎、方向盘等,而对于大多数用户而言,无须知道这些部件的装配细节,也几乎不会使用单独某个部件,而是使用一辆完整的汽车
  • 建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象
  • 建造者返还给客户端的是一个已经建造完毕的完整产品对象,而用户无须关心该对象所包含的属性以及它们的组装方式。

5.2 定义

  • 建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

包含以下角色

  • Builder:抽象建造者
  • ConcreteBuilder:具体建造者
  • Director:指挥者
  • Product:产品角色

5.3 模式分析

  • 引入指挥者类,一方面它隔离了客户与生产过 程;另一方面它负责控制产品的生成过程。

    image-20210623161840443

  • 在客户端代码中,无需关心产品对象的具体组装过程,只需确定具体的建造者类型即可

    image-20210623161955295

  • 优点

    • 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
    • 每一个具体建造者都相对独立,而与其他的具体建造者无关,用户使用不同的具体建造者即可得到不同的产品对象。
    • 可以更加精细地控制产品的创建过程。
    • 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合“开闭原则”。
  • 缺点

    • 如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
    • 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大
  • 适用

    • 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性。
    • 需要生成的产品对象的属性相互依赖,需要指定其生成顺序。
    • 对象的创建过程独立于创建该对象的类。在建造者模式中引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类中。
    • 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品
  • 简化

    • 省略抽象建造者角色:如果系统中只需要一个具体建造 者的话,可以省略掉抽象建造者。
    • 省略指挥者角色:在具体建造者只有一个的情况下,如 果抽象建造者角色已经被省略掉,那么还可以省略指挥 者角色,让Builder角色扮演指挥者与建造者双重角色。

5.4 例子

建造者模式可以用于描述KFC如何创建套餐:套餐是一个复杂对象,它一般包含主食(如汉堡、鸡肉卷等)和 饮料(如果汁、可乐等)等组成部分,不同的套餐有不同的组成部分,而KFC的服务员可以根据顾客的要求, 一步一步装配这些组成部分,构造一份完整的套餐,然后返回给顾客

image-20210623163044297

5.5 对比

通过前面的学习,我们已经了解了建造者模式,那么它和工厂模式有什么区别呢?

  • 建造者模式更加注重方法的调用顺序,工厂模式注重创建对象。
  • 创建对象的力度不同,建造者模式创建复杂的对象,由各种复杂的部件组成,工厂模式创建出来的对象都一样
  • 关注重点不一样,工厂模式只需要把对象创建出来就可以了,而建造者模式不仅要创建出对象,还要知道对象由哪些部件组成。
  • 建造者模式根据建造过程中的顺序不一样,最终对象部件组成也不一样。

6 原型模式 Prototype

image-20210623163926535

6.1 模式动机

  • 使用原型模式来复制一个对象自身, 从而克隆出多个与原型对象一模一样的对象
  • 在软件系统中,有些对象的创建过程较为复杂,而且有时候需要频繁创建,原型模式通过给出一个原型对象来指明 所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象,这就是原型模式的意图所在。

6.2 定义

  • 原型模式(Prototype Pattern):原型模式是一种对象创建型模式,用原型实例指定创建对象的种类,并且通过复 制这些原型创建新的对象。

  • 原型模式允许一个对象再创建另外一个可定制的对象,无须知道任何创建的细节。

原型模式包含如下角色:

  • Prototype:抽象原型类
  • ConcretePrototype:具体原型类
  • Client:客户类

6.3 模式分析

  • 一个类包含一些成员对象,在使用原型模式克隆对象时,根据其成员对象是否也克隆,原型模式可以分为两种形式:深克隆和浅克隆

  • JAVA中有clone方法

    • 所有的Java 类都继承自java.lang.Object,而Object类提供一个 clone()方法,可以将一个Java对象复制一份
    • 能够实现克隆的Java类必须实现一个标识接口Cloneable, 表示这个Java类支持复制。如果一个类没有实现这个接 口但是调用了clone()方法,Java编译器将抛出一个 CloneNotSupportedException异常。
    • 对任何的对象x,都有x.clone()!=x,即克隆对象与 原对象不是同一个对象。
    • 对任何的对象x,都有 x.clone().getClass()==x.getClass(),即克隆对象与原 对象的类型一样。
    • 如果对象x的equals()方法定义恰当,那么 x.clone().equals(x)应该成立。
  • 优点

    • 使用原型模式可以简化对象的创建过程,通过一个已有实例可以提高新实例 的创建效率。
    • 可以动态增加或减少产品类。
    • 原型模式提供了简化的创建结构。
    • 可以使用深克隆的方式保存对象的状态
  • 缺点

    • 需要为每一个类配备一个克隆方法,对已有的类进行改造时,不一定是件容易的事, 必须修改其源代码,违背了“开闭原则”。
    • 在实现深克隆时需要编写较为复杂的代码
  • 适用

    • 创建新对象成本较大
    • 如果系统要保存对象的状态,而对象的状态变化很小,或者对象本身占内存不大的时候
    • 需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少的几个组合状态,通过复制原型对象 得到新实例可能比使用构造函数创建一个新实例更加方便
  • 扩展

    • 原型管理器原型模式(原型设计模式)详解 (biancheng.net)

      image-20210623172117692

    • 相似对象的复制

      很多情况下,复制所得到的对象与原型对象并不是完全相同的,它们的某些属性值存在异同。通过原型模式获 得相同对象后可以再对其属性进行修改,从而获取所需对象。

6.4 例子

  • 原型模式应用于很多软件中,如果每次创建一个对象要花大量时间,原型模式是最好的解决方案。很多软件提 供的复制(Ctrl + C)和粘贴(Ctrl + V)操作就是原型模式的应用
  • 在Spring中,用户也可以采用原型模式来创建新的bean实例,从而实现每次获取的是通过克隆生成的新实例,对其进行修改时对原有实例对象不造成任何影响。
posted @ 2021-06-23 17:24  cpaulyz  阅读(217)  评论(0编辑  收藏  举报