设计模式之创建型模式

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 单例模式的使用场景

  • 某类只要求生成一个对象的时候,如一个航班的机长、每个人的身份证号等。
  • 当对象需要被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问 速度。如 Web 中的配置对象、数据库的连接池等。
  • 当某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。
  • 在计算机系统中, Windows 的回收站、操作系统中的文件系统、多线程中的线程池、显卡的驱动程序对象、 打印机的后台处理服务、应用程序的日志对象、数据库的连接池、网站的计数器、Web 应用的配置对象、应 用程序中的对话框、系统中的缓存等常常被设计成单例。

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 工厂方法模式的应用场景

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

  • 客户只知道创建产品的工厂名,而不知道具体的产品名。如 TCL 电视工厂、海信电视工厂等。
  • 创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
  • 客户不关心创建产品的细节,只关心产品的品牌。

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 原型模式

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容