第一部分:创建型模式

创建型模式抽象了实例化过程

它们帮助一个系统独立于怎样创建、组合和表示它的那些对象。(把一些小的对象组装成大对象,这个工作由专门的类对象来做)

一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化托付给还有一个对象。

随着系统演化得越来越依赖于对象复合而不是类继承,创建型模式变得更为重要。由于系统定义一个较小的行为集,这些行为能够被组合成随意数目的更复杂的行为。

(把行为分散在各类中。用对象组合的方式,依据须要组合成大类)

这些创建型模式有两个特点

1、它们都将关于该系统使用哪些详细的类的信息封装起来。

2、它们隐藏了这些类的实例是怎样被创建和组装在一起的。

创建型模式在什么被创建,谁创建它,如何被创建。以及何时创建这些方面给你非常大的灵活性。

(一)、抽象工厂(Abstract Factory)——对象创建型模式

意图:

提供一个 创建一系列相关或相互依赖对象的 接口,而无需指定它们详细的类。(用一个工厂类创建系统中相关连的对象)

引子:

考虑一个支持多种视感风格用户界面工具包。不同的视感风格为滚动栏、窗体和button等窗体组件定义不同的外观和行为。为保证视感风格间的可移植性,一个应用不应该为一个特定的视感外观编码它的窗体组件。

(考虑系统中哪些是未来可能变化的,一组相关的窗体组件。那么我们就封装变化,专门定义一个类来生成这一组相关的窗体组件。)

为解决这一问题,我们能够定义一个抽象的WidgetFactory类,这个类声明了一个用来创建每一类基本窗体组件的接口。每一类窗体组件都有一个抽象类。而详细子类则实现了窗体组件特定的视感风格。

WidgetFactory接口有一个返回新窗体组件对象的操作。

客户调用这些操作以获得窗体组件实例,但客户并不知道他们正在使用的是哪些详细类。这样客户就不依赖于一般的视感风格。

每一种视感标准都相应于一个详细的WidgetFactory子类。(比如。MotifWidgetFactory的CreateSrollBar实例化并返回一个Motif滚动栏。

客户仅通过WidgetFactory接口创建窗体组件,他们并不知道哪些类实现了特定视感的窗体组件。换言之。客户仅与抽象类定义的接口交互,而不使用特定的详细类的接口

(客户不知道用的是哪一套创建方案)

对于客户来说。其仅仅知道WidgetFactory、Window、SrollBar这三个抽象类。

适用:

1、一个系统要独立于它的产品的创建、组合和表示时

2、一个系统要由多个产品系列中的一个来配置时。

3、当你强调一系列相关的产品对象的设计以便进行联合使用时。

特点:

1、它分离了详细的类

由于一个工厂封装创建产品的责任和过程,它将客户与类的实现分离。

客户通过它们的抽象接口操纵实例。产品的类名也不出如今客户代码中。(比方:详细的产品类名ProductA1。客户使用产品的抽象类名AbstractProductA)

2、它使得易于交换产品系列

一个抽象工厂创建了一个完整的产品系列,仅仅需改变详细的工厂就可以使用不同的产品配置,整个产品系列会立马改变。

3、难以支持新种类的产品

难以扩展抽象工厂以生产新种类的产品。这是由于AbstractProduct接口确定了能够被创建的产品集合。

支持新种类的产品就须要扩展该工厂接口,这将涉及AbstractProduct类及其全部子类的改变。

代码演示样例:

为一个电脑游戏创建一个迷宫,我们将忽略很多迷宫中的细节以及一个迷宫游戏中有一个还是多个游戏者。我们仅关注迷宫是如何被创建的。

我们将一个迷宫定义为一系列房间,一个房间知道它的邻居。可能的邻居要么是还有一个房间。要么是一堵墙,或者是到还有一个房间的一扇门。

类Room、Door和Wall定义了我们全部的样例中使用到的构件。

我们将使用Abstract Factory模式创建这个迷宫。

类MazeFactory能够创建迷宫组件。它建造房间、墙壁和房间之间的门。 建造迷宫的程序将MazeFactory作为一个參数,这样程序猿就能指定要创建的房间、墙壁和门等类。

class MazeFactory

{

public:

MazeFactory() ;

virtual  Maze*   MakeMaze() const

{    return new Maze ;  }

virtual  Maze*   MakeWall() const

{    return new Wall ;  }

virtual  Maze*   MakeRoom(int n) const

{    return new Room(n) ;  }

virtual  Maze*   MakeDoor(Room* r1, Room* r2) const

{    return new Door(r1, r2) ;  }

} ;

//我们创建MazeFactory的子类EnchantedMazeFactory。这是一个创建施了魔法的迷宫的工厂。

//EnchantedMazeFactory将重定义不同成员函数并返回Room,Wall等不同的子类。

class EnchantedMazeFactory : public MazeFactory

{

public:

EnchantedMazeFactory() ;

virtual  Room*   MakeRoom(int n) const

{    return new   EnchantedRoom(n) ;    }

virtual  Maze*   MakeDoor(Room* r1, Room* r2) const

{    return new   DoorNeedingSpell(r1, r2) ;  }

} ;

//我们创建MazeFactory的子类BombedMazeFactory。这是一个炸弹毁坏过的迷宫的工厂

//Room的子类RoomWithABomb,Wall的子类BombedWall来表示炸过的房间和墙壁

class BombedMazeFactory : public MazeFactory

{

public:

BombedMazeFactory() ;

virtual  Maze*   MakeWall() const

{    return   new   BombedWall ;  }

virtual  Maze*   MakeRoom(int n) const

{    return   new   RoomWithABomb(n) ;  }

} ;

客户使用:

客户的CreateMaze函数。以MazeFactory为參数

Maze* MazeGame::CreateMaze (MazeFactory&factory)

{

Maze*  aMaze = factory.MakeMaze() ;

Room*  r1= factory.MakeRoom(1) ;

Room*  r2= factory.MazeRoom(2) ;

Door*  aDoor = factory.MakeDoor(r1, r2) ;

aMaze->AddRoom(r1) ;

aMaze->AddRoom(r2) ;

//用户自己组装(工厂仅仅负责创建)

r1->SetSide(North, factory.MakeWall()) ;

//......

return  aMaze ;

}

为创建一个包括炸弹的简单迷宫,我们仅用BombedMazeFactory调用CreateMaze。

MazeGame   game ;

BombedMazeFactory   factory ;

game.CreateMaze(factory) ;

通过抽象工厂来创建对象(面向接口编程),而不是自己直接创建,为什么要假手工厂来创建对象?由于灵活性,当我们要其他风格的对象时,换工厂即可了。

(由于接口不变。我们做的修改小)

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFuZ195dWxlaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

关键词:工厂

(二)、生成器(Builder)——对象创建型模式

意图:

将一个复杂对象的构建与它的表示分离。使得相同的构建过程能够创建不同的表示

【即把组装与生成分离,由一个类(生成器Builder)负责生成所需的配件,由还有一个类(向导器Director)负责组装配件成产品】

ConcreteBuilder创建该产品的内部表示并定义它的装配过程。

生成器逐步的构造它们的产品。因此Builder类接口必须足够普遍,以便为各种类型的详细生成器构造产品。

且注意:在Builder中缺省的方法为空,而不是纯虚函数,把它们定义为空方法,这使客户仅仅重定义他们所感兴趣的操作。

不同的生成器提供不同的小配件给向导器

协作:

1、客户创建Director对象,并用它所想要的Builder对象进行配置。

2、一旦产品部件被生成(导向器调Builder),导向器就会通知生成器。

(生成部件)

3、生成器处理导向器的请求。并将部件加入到该产品中。(组装)

4、客户从生成器中检索(获取)产品。

特点:

1、它使你能够改变一个产品的内部表示

Builder对象提供给导向器一个构造产品的抽象接口。该接口使得生成器能够隐藏这个产品的表示和内部结构。它同一时候也隐藏了该产品是怎样装配的。

2、它将构造代码和表示代码分开

客户不须要知道定义产品内部结构的类的全部信息,这些类是不出如今Builder接口中的。每一个实际的生成器包括了创建和装配一个特定产品的全部代码。

3、它使你可对构造过程进行更精细的控制

Builder模式与一下子就生成产品的创建型模式不同。它是在导向者的控制下一步一步构造产品的。

仅当该产品完毕时导向者才从生成器中取回它。(导向者控制装配的顺序)

代码举例:

以创建迷宫为例:

一个CreateMaze函数专门用来创建迷宫,它以类MazeBuilder的一个生成器对象作为參数。

class MazeBuilder

{

public:

virtual  void   BuildMaze() { }

virtual  void   BuildRoom(int room) { }

virtual  void   BuildDoor(int roomFrom, int roomTo) { }

virtual  Maze*   GetMaze() {  return 0;  }

protected:

MazeBuilder() ;

} ;

该接口可创建:1、迷宫(空架子) 2、有一个特定房间号的房间 3、在有号码的房间之间的

GetMaze操作返回这个迷宫给客户。 MazeBuilder的子类将重定义这些操作。返回它们所创建的迷宫。

注意MazeBuilder自己并不创建迷宫。它的主要目的不过为创建迷宫定义一个接口。MazeBuilder的子类做实际工作

class StandardMazeBuilder : public MazeBuilder

{

public:

StandardMazeBuilder() ;

virtual  void   BuildMaze() ;

virtual  void   BuildRoom(int) ;

virtual  void   BuildDoor(int, int) ;

virtualMaze*   GetMaze() ;

private:

Direction   CommonWall(Room*, Room*) ;

Maze*  _currentMaze ;

} ;

void StandardMazeBuilder::BuildMaze()   //向构造一个空的Maze。再逐步往里面加东西。

{

_currentMaze = new Maze ;

}

void StandardMazeBuilder::GetMaze()

{

return  _currentMaze  ;

}

//BuildRoom操作创建一个房间并建造它周围的墙壁

void StandardMazeBuilder::BuildRoom(int n)

{

if(!_currentMaze->RoomNo(n))

{

Room*  room = new Room(n) ;

_currentMaze->AddRoom(room) ;

//创建Room周围的墙壁

room->SetSide(North, new Wall) ;

room->SetSide(South, new Wall) ;

room->SetSide(East, new Wall) ;

room->SetSide(West, new Wall) ;

}

}

//.......

导向器上场:其定义了组装的流程(向建一个Maze框架,再填充两个Room,再在两房子之间填充Door)

Maze* MazeGame::CreateMaze(MazeBuilder& builder)

{

builder.BuildMaze() ;

builder.BuildRoom(1) ;

builder.BuildRoom(2) ;

builder.BuildDoor(1, 2) ;

returnbuilder.GetMaze() ;

}

用户使用:用户如今能够用CreateMaze和StandardMazeBuilder来创建一个迷宫

Maze* maze ;

MazeGame game ;

StandardMazeBuilder builder ;

game.CreateMaze(builder) ;//CreateMaze依据其定义的流程去指导builder逐步创建、组装好产品。

maze = builder.GetMaze() ;

抽象工厂VS 生成器

两者的目的不同,抽象工厂就是生产一些相关的产品给用户,用户怎么用这些产品其不关心。生成器就是生产一些小部件,由导向器来装配这些部件,组装成一个产品。

抽象工厂是一个工厂。一个工厂里生产各种产品(这些产品都是相关的)。它提供给用户的是多个接口,每一个接口产生一个产品。

抽象工厂与生成器相似。由于它也能够创建复杂对象。基本的差别是Builder模式着重于一步步构造一个复杂对象。而抽象工厂着重于多个系列的产品对象(简单的或是复杂的)。

Builder在最后一步返回产品,而对于抽象工厂来说。产品是马上返回的

关键词:装配

面向程序猿的设计模式 ——GoF《设计模式》读书总结(壹)抽象工厂&生成器的更多相关文章

  1. Java设计模式从精通到入门五 抽象工厂方法模式

    定义 抽象工厂类为创建一组相关和相互依赖的对象提供一组接口,而无需指定一个具体的类. ​ 这里我得把工厂方法模式得定义拿出来做一下比较:定义一个创建对象的接口,由子类决定实例化哪一个类.工厂方法是一个 ...

  2. 大话设计模式C++实现-第15章-抽象工厂模式

    一.UML图 二.概念 抽象方法模式(Abstract Factory):提供一个创建一系列相关或互相依赖对象的接口,而无需指定他们详细的类. 三.包括的角色 (1)抽象工厂 (2)详细工厂:包含详细 ...

  3. 设计模式成长记(一) 抽象工厂模式(Abstract Factory)

    目录 定义 UML类图 参与者 编写代码 特点 定义 提供一个创建一系列相关或相互依赖的对象的接口,而无需指定具体的类. 使用频率: UML类图 参与者 AbstractFactory:声明一个创建抽 ...

  4. Python中异常打印——面向程序猿

    import logging # logging.disable(logging.CRITICAL) logging.basicConfig(filename="loggingBug.txt ...

  5. GoF23种设计模式之创建型模式之抽象工厂模式

    一.概述 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 二.适用性 1.一个系统要独立于它的产品的创建.组合和表示的时候. 2.一个系统要由多个产品系列中的一个来配置的时候. ...

  6. java之设计模式工厂三兄弟之抽象工厂模式

    [学习难度:★★★★☆,使用频率:★★★★★]  工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工 ...

  7. headfirst设计模式(5)—工厂模式体系分析及抽象工厂模式

    先编一个这么久不写的理由 上周我终于鼓起勇气翻开了headfirst设计模式这本书,看看自己下一个设计模式要写个啥,然后,我终于知道我为啥这么久都没写设计模式了,headfirst的这个抽象工厂模式, ...

  8. 设计模式 — 抽象工厂模式(Abstract Factory)

    工厂模式已经分析了简单工厂模式和工厂方法模式.并且了解了工厂方法模式去简单工厂模式的延伸,工厂方法模式如果不把工厂类抽象的话,就是简单工厂模式.由前面两个工厂模式可以猜测出抽象工厂模式应该是这两种工厂 ...

  9. Java设计模式学习笔记(四) 抽象工厂模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 抽象工厂模式概述 工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问 ...

随机推荐

  1. HDOJ 4944 FSF’s game

    http://blog.csdn.net/keshuai19940722/article/details/38519681 不明真相的补一发... FSF's game Time Limit: 900 ...

  2. 启用QNX系统,海尔智能冰箱或成业界“宝马”

        智能家电正处于迅猛发展的态势,国内眼下有非常多企业都在积极布局智能家电,当中又以海尔最为典型.作为家电领域的领头羊,海尔近年来在智能家电领域的动作不小.近期有消息透露.海尔也许会在IFA展会上 ...

  3. 2014年湖北省TI杯大学生电子设计竞赛论文格式

    2014年湖北省TI杯大学生电子设计竞赛 B题:金属物体探測定位器(本科) 2014年8月15日 文件夹 1 系统方案 1.1 XXX的论证与选择........................... ...

  4. python spark kmeans demo

    官方的demo from numpy import array from math import sqrt from pyspark import SparkContext from pyspark. ...

  5. React 父组件触发子组件事件

    Parent组件 import React from "react"; import Child from "./component/Child"; class ...

  6. .NET CORE MVC网站体验

    安装SDK https://www.microsoft.com/net/download/core 运行命令行工具 mkdir coremvc cd coremvc dotnet new 文件建立成功 ...

  7. 有关windows dpi适配(c#)

    /// <summary>当前Dpi</summary> public static Int32 Dpi { get; set; } /// <summary>修正 ...

  8. genemotion

    genemotion 问题 https://blog.csdn.net/beiminglei/article/details/17399333 https://www.jianshu.com/p/f8 ...

  9. 修改properties文件后系统运行异常

    今天修改了项目的properties配置文件以后,运行会报异常,即使将内容改回,异常仍然存在.中间还会出现项目报错等问题,现将解决方法整理出来. 1.修改properties的打开方式,将打开方式从p ...

  10. ZBrush中标准笔刷介绍

    ZBrush最实用.精彩的部分便是雕刻了,笔刷又有时雕刻时必不可少的工具,ZBrush中给我们提供了很多种笔刷,那么,最基础.最常用的笔刷是什么呢,本文内容向大家介绍ZBrush®中标准笔刷以便大家熟 ...