@IT·互联网

设计模式之创建型模式

2021-04-03  本文已影响0人  苦难_69e0

2、 设计模式之创建型模式

创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是“将对象的创建与使用分离”。这样可以降低系统的 耦合度,使用者不需要关注对象的创建细节,对象的创建由相关的工厂来完成。就像我们去商场购买商品时,不需 要知道商品是怎么生产出来一样,因为它们由专门的厂商生产。

创建型模式分为以下几种。

image.png

2.1 单例模式

2.1.1 什么是单例模式?(概念的引入)

案例:我是皇帝,独此一家。

中国自从秦始皇确立了皇帝这个职位之后,同一个时期基本上上就只有一个人孤零零的坐在皇位上啦。这种情况的 好处就是大家好办事,大家讨论或者汇报大事的时候只要提及皇帝,每个人都知道指的是谁,不需要在皇帝面前加 上特定的称呼。这种过程反应到软件设计领域就是:一个类只能产生一个对象(皇帝),大家对他的依赖都是相同 的。我们把皇帝这种特殊的职位通过程序来实现。

皇帝类:


image.png

大臣类:


image.png

运行结果:


image.png

大臣每天上朝汇报国事的对象都是同一个皇帝,这就是单例模式!

2.1.2 单例模式的定义以及特点

定义:

确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
Ensure a class has only one instance,and provide a global point of access to it.

特点:

2.1.3 单例模式的分类

上面的单例模式,在低并发的情况下可能不会出现问题,如果并发量增大,内存中就会出现多个实例,就不是真正 意义上的单例。为什么会出现这种情况呢?

解决线程不安全的方式有多种。我们先将上面代码的单例模式修改为线程安全的:

懒汉式单例:

image.png

该模式的特点是类加载时没有生成单例,只有当第一次调用 getlnstance 方法时才去创建这个单例。

关键字 volatile 和 synchronized,能保证线程安全,但是每次访问时都要同步,会影响性能,且消耗更多的资 源,这是懒汉式单例的缺点。

饿汉式单例:

image.png

该模式的特点是类一旦加载就创建一个单例,保证在调用 getInstance 方法之前单例已经存在了。而且该方式是线 程安全的。

2.1.4 单例模式的使用场景

2.1.5 单例模式的优缺点

优点:

缺点:

2.1.6 单例模式的扩展

单例模式可扩展为有限的多例(Multitcm)模式,这种模式可生成有限个实例并保存在 ArrayList 中,客户需要时 可随机获取。

image.png

大臣类:

image.png

运行结果:PS:每个人的运行结果都不一样,因为随机数的产生不一致

image.png

2.2 工厂方法模式

2.2.1 什么是工厂模式?

引入案例:话说前一阵疫情期间,居家的时间有点长,于是我也跟广大网友一样,开始好好修炼自己的厨艺,有人 做凉皮,有人做锅巴。我也加入了霍霍面粉的大军--做面包。

于是和面、发面、捏成我想要的布朗熊的样子,开心放入烤箱 ,等待我的布朗熊面包出炉。然而,步骤没错,烤箱 没错,可能是大厨不对:

第一次:时间稍短了点,没太烤熟,于是布朗熊面包变成了北极熊面包;

再来一次:时间长点肯定能熟了,烤箱中多靠一会,出炉发现烤焦啦,与布朗熊面包变成了黑熊面包;

第三次:吸取教训,别跟时间死磕了,一直盯着烤箱中的面包好了,等到面包微微发焦,终于成功的做出了我想要 的布朗熊面包

好在家人给面子,每一种面包都有人吃掉哈。

在这个过程中,我的职业病就犯了,是不是可以通过软件开发来实现这个过程呢?

在面向对象的思想中,万物皆对象。是对象我们就可以通过软件设计来实现。来分析一下烤面包的过程,该过程涉 及三个对象:大厨(也就是我哈)、烤箱、三种不同成果的面包(我称他们为北极熊、黑熊、布朗熊)。

大厨可以使用场景类Client来表示,烤箱类似一个工厂,负责生产产品(即面包),三种不同成果的面包都是一个 接口下不同实现类,因为好不好吃好不好看也都是面包啊。

image.png image.png image.png image.png image.png

2.2.2 工厂方法模式的定义

定义:

定义一个用户创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

工厂方法模式的主要角色如下:

  1. 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 newProduct() 来创建产品。
  2. 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  3. 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
  4. 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对 应。

我们可以将工厂方法模式抽取出一个实用的通用代码:

image.png

2.2.3 工厂方法模式的应用场景

工厂方法模式通常适用于以下场景。

2.3 抽象工厂模式

2.3.1 引入案例:

上回书说到我的烤面包副业已经小有成就,做的多了发现我的面包似乎缺少了灵魂,面包怎么能没有馅儿呢?!于 是打算将自己最爱的水果菠萝和芒果放入面包中。

大厨烤面包之前也是做了很多的准备工作的,所以想在不浪费现有资源的情况下继续完成新产品的制作。之前做的 面包中虽然大厨自己觉得布朗熊面包才是最成功的的,但是每个人的口味不一样,有人偏爱烤的过火的,有的偏爱 稍欠火候的。所以我决定继续满足所有人的口味:即将做出三种火候的菠萝面包和芒果面包。

即将要做的产品分析完了,可是我的工厂(面包机)真真只有一个烤面包的功能,于是为了做出蛋糕,又专门买了 一个烘焙蛋糕的烤箱。于是乎,可以准备干活啦!

image.png image.png image.png image.png

所有产品都出炉啦!

image.png

工厂方法模式只考虑生产同等级的产品,抽象工厂模式将考虑多等级产品的生产,将同一个具体工厂所生产的位于 不同等级的一组产品称为一个产品族。

2.3.2 模式的定义与特点

抽象工厂(AbstractFactory)模式的定义:为创建一组相关或者相互依赖的对象提供一个接口,而且无须指定他们 的具体类。

抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是 一种非常好的解决方案。工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。

使用抽象工厂模式一般要满足以下条件。

2.3.3 抽象工厂的通用代码

image.png image.png image.png

2.3.4 抽象工厂模式的优缺点:

优点:

其缺点是:当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。

2.3.5 抽象工厂模式的应用场景

  1. 适合于产品之间相互关联、相互依赖且相互约束的地方
  2. 需要动态切换产品族的地方

2.4 建造者(Builder)模式

2.4.1 案例引入

老板:又签订了一个新合同,XX公司将宝马和奔驰两款车辆模型都交给我们公司制作了。不过这次有了新的需求: 汽车的启动、停止、鸣笛、引擎声音都由客户自己控制,他们想要什么顺序就什么顺序,OK吗?

我:OK!

来分析一下需求:宝马和奔驰两款车辆模型都是产品,他们有共有的属性,XX公司关心的是每个模型的运行过程, 期待奔驰A模型先有引擎声音再鸣笛,奔驰B模型是先启动再有引擎声音。老板的意思就是满足客户所有要求,要 什么顺序立刻就生成什么顺序的模型出来,而且能批量生成出来。

使用程序模拟实现这一需求:

image.png image.png image.png image.png image.png

看到运行结果,满足了一个需求,如果还有更多的不同顺序的需求怎么办呢?不停的写场景类来满足吗?很显然这 是一个问题,所以我们就要想一种方案来解决这个问题。

我们为每种产品模型定义一个建造者,要创建什么顺序直接通知建造者,由建造者来建造。使用程序模拟一下:

image.png image.png image.png

同样运行顺序的宝马车也出来了,而且代码比第一版直接访问产品类简单清晰。

我们在做项目的时候要知道:需求不可能一成不变的。我们案例中的4个过程(start stop alarm engineboom)按 照组合有很多种。客户可以随意组合,它是上帝,想要什么顺序我就要生成什么顺序的车模。怎么办呢?我们就需 要封装一下,找个导演来指挥各个事件的先后顺序,然后为每种顺序指定一个代码,你要什么我们立刻就可以提 供。

image.png image.png

有了这样的导演类之后,我们的场景类就更容易处理了。而且代码变得简单清晰。

其实我们上面用的就是建造者模式!

其实生活中还有更多的这样的案例。例如,计算机是由 OPU、主板、内存、硬盘、显卡、机箱、显示器、键盘、 鼠标等部件组装而成的,采购员不可能自己去组装计算机,而是将计算机的配置要求告诉计算机销售公司,计算机 销售公司安排技术人员去组装计算机,然后再交给要买计算机的采购员。

再例如游戏中的不同角色,其性别、个性、能力、脸型、体型、服装、发型等特性都有所差异;还有汽车中的方向 盘、发动机、车架、轮胎等部件也多种多样;每封电子邮件的发件人、收件人、主题、内容、附件等内容也各不相 同。

以上所有这些产品都是由多个部件构成的,各个部件可以灵活选择,但其创建步骤都大同小异。这类产品的创建无 法用前面介绍的工厂模式描述,只有建造者模式可以很好地描述该类产品的创建。

2.4.2 模式的定义与结构

2.4.2.1 建造者模式的定义:

指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者 模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组 成部分是不变的,但每一部分是可以灵活选择的。

2.4.2.2 模式的结构与实现

1. 模式的结构

建造者模式的主要角色如下。

  1. 产品(Product)类:它是包含多个组成部件的复杂对象,由具体建造者来创建其各个部件。
  2. 抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产 品的方法 getResult()。
  3. 具体建造者(Concrete Builder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。
  4. 导演(Director)类:它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具 体产品的信息。

2. 模式的实现

image.png image.png image.png image.png image.png

2.4.3 建造者模式的优缺点

优点:

  1. 各个具体的建造者相互独立,有利于系统的扩展。
  2. 客户端不必知道产品内部组成的细节,便于控制细节风险。

缺点:

  1. 产品的组成部分必须相同,这限制了其使用范围。
  2. 如果产品的内部变化复杂,该模式会增加很多的建造者类。

建造者(Builder)模式和工厂模式的关注点不同:建造者模式注重零部件的组装过程,而工厂方法模式更注重零 部件的创建过程,但两者可以结合使用。

2.4.4 模式的应用场景

建造者(Builder)模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算 法却相对稳定,所以它通常在以下场合使用。

2.5 原型模式

上一篇下一篇

猜你喜欢

热点阅读