设计模式(2)创造型设计模式

创建型模式

  • 创建型模式
      • 1.工厂模式
          • 1.1 抽象工厂模式(Abstract factory)
          • 1.2 工厂方法模式(Factory Method)
          • 1.3 简单工厂模式(Simple Factory)
      • 2. 建造者模式(Builder)
      • 3. 原型模式(Prototypes)
      • 4. 单例模式
      • 5. 创建型模式之间的联系和区别

创建型模式

前提:为一个电脑游戏创建一个迷宫,忽略迷宫的诸多细节,仅仅关注迷宫是怎样被创建的。

定义:将迷宫定义为一系列房间(Room),房间的四面要么是一堵墙(Wall),要么是一扇门(Door)。

//房间四个面
enum Direction{ North, South, East, West};
//房间
class Room{...}
//墙
class Wall{...}
//门
class Door{...}
//迷宫
class Maze{...}
//迷宫游戏
class MazeGame{...}

一个简单的迷宫创建函数,如下:

Maze* MazeGame::CreateMaze()
{Maze *aMaze = new Maze;Room *r1 = new Room(1);Room *r2 = new Room(2);Door *dr = new Door(r1,r2);aMaze->addRoom(r1);aMaze->addRoom(r2);r1->setSide(North, new Wall);r1->setSide(South, dr);r1->setSide(East, new Wall);r1->setSide(West, new Wall);r2->setSide(North, new Wall);r2->setSide(North, new Wall);r2->setSide(North, new Wall);r2->setSide(North, dr);return aMaze;
}

这个函数的缺点在于: 对迷宫布局硬编码,改变布局意味着需要改变这个函数本身,容易产生错误,且不利于重利用。试想一下,重用该迷宫的布局,但是迷宫中的部件和来原来不一致了,例如现在的门是施了魔法的,需要咒语才能开启等等。在这种情况下,改变的最大障碍就是对被实例化的类进行硬编码。

创建型模型提供了多种不同方法从实例化它们的代码中除去对这些具体类的显示引用:

  1. 如果CreateMaze调用虚函数而不是显式构造来创建它需要的房间、门和墙壁;那么可以通过创建一个MazeGame的子类并重定义这些虚函数,从而改变被实列化的类。正如工厂方法模式
  2. 如果传递一个对象给CreateMaze作参数来创建房间、墙壁和门,那么可以通过传递不同的参数来改变这些部件的类。正如抽象工厂模式
  3. 如果传递一个对象给CreateMaze,这个对象可以在它所建造的迷宫中增加房间、墙壁和门的操作,来创建一个新的迷宫。那么可以通过继承当方式来改变迷宫被建造的方式,正如建造者模式
  4. 如果CreateMaze由多种原型的房间、墙壁和门对象参数化,它拷贝并将这些对象增加到迷宫中。正如原型模式
  5. 单例模式可以保证每个游戏中仅有一个迷宫存在,而且所有的游戏对象都可以迅速的访问它。

1.工厂模式

工厂模式定义:
工厂模式(Factory Pattern)是一种创建型设计模式,它提供了一种创建对象的接口,而无需指定它们具体的类,实例化的类是哪一个由子类决定。工厂模式将对象的实例化过程封装在一个工厂类中,使得客户端代码与具体类解耦,提供了一种灵活、可扩展的对象创建机制。

工厂模式的核心思想是将对象的创建过程封装在工厂类中,客户端代码通过与工厂类进行交互来获取所需的对象,而不需要直接实例化具体产品类。这种解耦的设计使得客户端代码更加灵活,可以通过切换具体工厂类来创建不同的产品对象。

工厂模式有以下几种常见的变体:

  1. 简单工厂模式(Simple Factory Pattern):使用一个单独的工厂类来创建所有的产品对象,通过传递不同的参数给工厂方法来选择创建哪种产品
  2. 工厂方法模式(Factory Method Pattern):每个具体产品都有对应的工厂类,客户端通过调用具体工厂类来创建具体产品对象
  3. 抽象工厂模式(Abstract Factory Pattern):提供一个抽象工厂接口,具体工厂类实现该接口并负责创建一系列相关或相互依赖的产品对象(把一系列工厂方法归结到一起)
1.1 抽象工厂模式(Abstract factory)

抽象工厂结构图:
在这里插入图片描述

在抽象工厂模式中,通常有以下几个角色:
抽象工厂(Abstract Factory):定义了创建产品的接口,包含了创建产品的抽象方法。
具体工厂(Concrete Factory):实现了抽象工厂接口,负责实际创建具体产品的对象。
抽象产品(Abstract Product):定义了产品的接口,是具体产品类的共同父类或接口。
具体产品(Concrete Product):实现了抽象产品接口,是工厂模式所创建的对象。

用抽象工厂来实现迷宫创建,代码如下:

class MazeFactory
{virtual Maze *MakeMaze(){return new Maze;}virtual Wall *MakeWall(){return new Wall;}virtual Room *MakeRoom(int n){return new Room(n);}virtual Door *MakeDoor(Room* r1, Room* r2){return new Door(r1,r2);}
}
//建造迷宫的程序使用MazeFactory作为参数,程序便能指定创建的房间、门、墙壁类型
Maze* MazeGame::CreateMaze(MazeFactor& factory)
{Maze *aMaze = factory.MakeMaze();Room *r1 = factory.MakeRoom(1);Room *r2 = factory.MakeRoom(2);Door *dr = factory.MakeDoor(r1,r2);aMaze->addRoom(r1);aMaze->addRoom(r2);r1->setSide(North, factory.MakeWall());r1->setSide(South, dr);r1->setSide(East, factory.MakeWall());r1->setSide(West, factory.MakeWall()l);r2->setSide(North, factory.MakeWall());r2->setSide(North, factory.MakeWall());r2->setSide(North, factory.MakeWall());r2->setSide(North, dr);return aMaze;
}
//创建一个MazeFactory的子类EnchanteMazeFactory,这是一个创建了施加魔法的迷宫工厂,EnchanteMazeFactory将重定义不同的成员函数并返回Room、Wall等不同的子类
class EnchanteMazeFactory : public MazeFactory
{...
}
//创建迷宫
MazeGame game;
EnchanteMazeFactory  factory;
game.CreateMaze(factory);
1.2 工厂方法模式(Factory Method)

工厂方式模式定义:
定义一个用于创建对象的接口,让子类决定实例化具体的类。Factory Method使一个类的实例化延迟到其子类中。

工厂方法结构图,如下:
在这里插入图片描述
适用性:

  • 当一个类不知道它所必须创建的对象的类的时候。
  • 当一个类希望由它的子类来指定它所创建的对象的时候。

工厂方法的一个潜在问题是它们可能为了创建适当的Product对象而迫使你创建Creator的子类,在c++种可以通过模板解决这种问题,如下:

class Creator
{virtual Product* CreateProduct() = 0 ;
}template <class TheProduct>
class StanderdCreator : public Creator
{virtual Product* CreateProduct();
}
template <class TheProduct>
Product* StanderdCreator<TheProduct>::CreateProduct()
{return new TheProduct;
}
//使用这个模板,客户只需要提供产品类
class MyProduct : public Product
{...
}
//使用
StanderdCreator<MyProduct> mycreator;

用工厂方法模式来实现迷宫创建,代码如下:

class MazeGame()
{Maze * CreateMaze();//工厂方法,推迟到子类中实现virtual Maze* makeMaze(){ return new Maze; }virtual Room* makeRoom(int n){ return new Room(n); }virtual Wall* makeWall(){ return new Wall; }virtual Door* makeDoor(Room* r1, Room* r2){ return new Door(r1,r2); }
}Maze* MazeGame::CreateMaze()
{Maze *aMaze = makeMaze();Room *r1 = makeRoom(1);Room *r2 = makeRoom(2);Door *dr = makeDoor(r1,r2);aMaze->addRoom(r1);aMaze->addRoom(r2);r1->setSide(North, makeWall());r1->setSide(South, dr);r1->setSide(East, makeWall());r1->setSide(West, makeWall());r2->setSide(North, makeWall());r2->setSide(North, makeWall());r2->setSide(North, makeWall());r2->setSide(North, dr);return aMaze;
}//不同的游戏可以创建MazeGame子类以特别指明一些迷宫的部件,MazeGame子类可以重定义所有或者部分工厂方法以指定产品中的变化,如下
class BombedMazeGame : public MazeGame
{virtual Wall* makeWall(){ return new BombedWall; }virtual Room* makeRoom(int n){ return new RoomWithABomb(n); }
}
1.3 简单工厂模式(Simple Factory)

简单工厂模式定义:也称为静态工厂模式,是一种创建型设计模式,它通过一个工厂类来封装对象的创建过程,根据客户端的请求返回不同的具体对象。简而言之就是在实现过程中通过指定参数来创建相应的产品。

class Creator
{virtual Product* Create(ProductId id){if(id == MINE) return new MyProduct;if(id == YOURS) return new YoursProduct;return 0;}
}
//子类可以重写Product,并引入新的标识
class MyCreator : public Creator
{virtual Product* Create(ProductId id){if(id == MINE) return new YoursProduct;if(id == YOURS) return new MyProduct;if(id == THRIRS) return new ThierProduct;return Creator::Create(id);return 0;}
}

2. 建造者模式(Builder)

建造者模式的定义:将一个复杂对象的构建与其表示(定义)分离,使得同样的构建过程可以创建不同的表示。
建造者模式的核心思想是将一个复杂对象的构建过程分解为多个简单的步骤,每个步骤由具体建造者来实现。通过指挥者将这些步骤按照一定的顺序组合起来,最终构建出一个完整的复杂对象。这样,客户端代码只需要与指挥者进行交互,而无需关心具体的构建过程和细节。

建造者模式适用于以下情况:

  • 当需要创建的对象具有复杂的内部结构,且内部部件的构建顺序和组合方式不稳定或多变时。
  • 当需要创建的对象的配置选项较多,构造函数参数过多且难以维护时。
  • 当希望通过一种统一的方式构建不同表示的对象时。

建造者模式结构图:
在这里插入图片描述
用建造者模式来实现迷宫创建,代码如下:

//MazeBuilder类定义下面的接口来创建迷宫
class MazeBuilder
{//复杂对象的构建过程分解为多个简单的步骤,每个步骤由具体建造者来实现virtual void BuildMaze(){}virtual void BuildRoom(int n){}virtual void BuildDoor(int roomFrom, int rootTo){}virtual Maze* GetMaze(){return 0;}
};Maze* MazeGame::CreateMaze(MazeBuilder& builder)
{builder.BuildMaze();builder.BuildRoom(1);builder.BuildRoom(2);builder.BuildDoor(1,2);return builder.GetMaze();
}
//子类StandarMazeBuilder实现了简单迷宫的创建
class StandarMazeBuilder : public MazeBuilder
{...
}
//创建迷宫
Maze * maze;
MazeGame game;
StandarMazeBuilder  builder;
maze = game.CreateMaze(builder);

3. 原型模式(Prototypes)

原型模式定义:原型模式(Prototype Pattern)是一种创建型设计模式,它通过复制现有对象来创建新的对象,而无需通过调用构造函数来创建。原型模式基于对象的克隆来创建新的对象,可以避免重复创建相似对象的开销。

原型模式的优点包括:

  • 可以避免重复创建相似对象的开销,提高创建对象的效率。
  • 可以通过克隆来动态地创建对象,无需依赖具体类。
  • 可以在运行时动态添加和删除原型对象。

原型模式的主要缺陷:每一个Protoypes子类都必须实现Clone操作,当类已经存在时就难以新增Clone操作,或当内部包括一些不支持拷贝或由循环引用的对象时,实现克隆可能会很困难。

原型模式特别适用于以下情形:

  • 创建一个对象需要消耗的资源较多,如数据读取、硬件访问等,可以通过原型复制来提高性能
  • 系统需要大量相同或相似对象(例如,克隆已有对象,改变值以指定新对象)的时候,可通过复制原型的方式来减少创建对象的开销
  • 对象的状态满足上述描述,并且状态需要持续变化的场景中,可以选择原型模式。

原型模式结构图,如下:
在这里插入图片描述
当实现原型时,可以考虑下面一些问题:

  1. 使用一个原型管理器。使用一个注册表存储和检索原型。在克隆一个原型前向注册表请求该原型。原型管理器是一个关联存储器,它返回一个与给定关键字相匹配的原型。
  2. 原型需要实现clone操作。
  3. 原型clone后的初始化操作。

用原型模式来实现迷宫创建(相关类声明在抽象工厂章节),代码如下:

class MazePrototypeFactory : public MazeFactory
{MazePrototypeFactory(Maze* m, Wall* w, Room* r, Door* d){_prototypeMaze = m;_prototypeRoom = r;_prototypeWall = w;_prototpyeDoor = d;}virtual Maze *MakeMaze(){return _prototypeMaze->clone();}virtual Wall *MakeWall(){return _prototypeWall->clone();}virtual Room *MakeRoom(int n){Room* r = _prototypeRoom->clone();r->init(n);return r;}virtual Door *MakeDoor(Room* r1, Room* r2){Door* d = _prototpyeDoor->clone();d->init(r1,r2);return d;}Maze* _prototypeMaze;Room* _prototypeRoom;Wall* _prototypeWall;Door* _prototpyeDoor;
}//创建迷宫
MazeGame game;
MazePrototypeFactory factory(new Maze, new Wall, new Room, new Door);
Maze * maze = game.CreateMaze(factory);

4. 单例模式

单例模式定义:单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供了一个全局访问该实例的入口点。

单例模式优点:

  • 提供了对唯一实例的全局访问点,方便其他类使用该实例。
  • 避免了重复创建对象的开销,节省了系统资源。
  • 确保了对象的一致性,因为只有一个实例存在。

单例模式的两种实现:

  • 懒汉模式

    class Singletion;
    Singletion* Singletion::sing = NULL;
    class Singletion
    {
    public://方式1static Singletion *creat_singletion(){if (!sing){lock();if(!sing){sing = new Singletion();}unlock();}return sing;}//由于双检锁失败的原因,这里提供方式2static Singletion& create_singletion1(){static Singletion sing1;return sing1}void task(){cout << "singtion task ..." << endl;}
    private:Singletion();Singletion(Singletion&);Singletion(Singletion&&);Singletion& operator=(const Singletion&);static Singletion *sing;//添加无智能指针时删除https://www.cnblogs.com/ring1992/p/9592817.html
    }
    //单例模板https://www.cnblogs.com/sunchaothu/p/10389842.html
    
  • 饥汉模式

    class Singletion
    {
    public:Singletion* get_instance(){return sing;}	void task (){//task}
    private:Singletion();Singletion(Singletion&);Singletion(Singletion&&);Singletion& operator=(const Singletion&);static Singletion *sing;
    }
    Singletion* Singletion::sing = new Singletion();
    

5. 创建型模式之间的联系和区别

  1. Abstract Factory和Builder相似,两者都可以创建复杂的对象。主要的区别是builder模式着重于一步一步构造一个复杂对象,而Abstract Factory着重于多个系列的产品对象。
  2. Abstract Factory模式可以通过Factory Method模式或者Builder模式来实现。
  3. Prototype和Abstract Factory模式在某种方面是相互竞争的,但是它们也可以一起使用。Abstract Factory可以存储一个被克隆的原型集合,并且通过集合返回大量对象。
  4. 在一个框架系统中,用一个系统创建的抽象类对系统进行参数化(CreateMaze函数)的方式有两种:
    a.生成创建对象的子类,比如工厂方法模式,这种方法的缺点在于,如果要改变产品类,就需要创建一个新的子类。
    b.定义一个对象负责明确产品对象的类,并将它作为该系统的参数,比如抽象工厂、原型模式、建造者模式。抽象工厂由这个工厂对象产生多个类的对象;建造者由这个工厂对象使用一个复杂协议逐步创建一个复杂产品;原型模式由该工厂对象通过拷贝原型对象来创建产品。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/682093.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据库原理及应用】期末复习汇总高校期末真题试卷03

试卷 一、选择题 1 数据库中存储的基本对象是_____。 A 数字 B 记录 C 元组 D 数据 2 下列不属于数据库管理系统主要功能的是_____。 A 数据定义 B 数据组织、存储和管理 C 数据模型转化 D 数据操纵 3 下列不属于数据模型要素的是______。 A 数据结构 B 数据字典 C 数据操作 D…

了解tensorflow.js

1、浏览器中进行机器学习的优势 浏览器中进行机器学习&#xff0c;相对比与服务器端来讲&#xff0c;将拥有以下四大优势&#xff1a; 不需要安装软件或驱动&#xff08;打开浏览器即可使用&#xff09;&#xff1b;可以通过浏览器进行更加方便的人机交互&#xff1b;可以通过…

今天又发现一个有意思的问题:SQL Server安装过程中下载报错,证明GPT是可以解决问题的

我们在安装数据库的时候&#xff0c;都会有报错问题&#xff0c;无论是Oracle、SQL Server、还是MySQL&#xff0c;都会遇到各种各样的报错&#xff0c;这归根到底还是因为电脑环境的不同&#xff0c;和用户安装的时候&#xff0c;操作习惯的不一样导致的问题。今天的问题是&am…

C++语言·string类

1. 为什么有string类 C语言中&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列的库函数(strcpy,strcat)&#xff0c;但是这些库函数与字符串是分离开的&#xff0c;不太符合OOP(Object Oriented Programming面向对…

加密“发射台”:未来通信的新模式

随着区块链技术的飞速发展&#xff0c;加密“发射台”作为一种新兴的安全通信工具&#xff0c;正逐渐受到关注。本文将从专业角度深入探讨加密“发射台”的概念、原理、应用场景及其未来发展趋势&#xff0c;以期为读者提供有深度和逻辑性的思考。 一、加密“发射台”的概念与…

Python turtle库 实现 随机彩色文字平面批量输出

# -*- coding: utf-8 -*- """ Spyder Editor This is a temporary script file. """ import turtle import random import turtle as t t.colormode(255) turtle.bgcolor("white") h255 l50#字号 m60#间隔 n500 t.penup() turtle.hide…

【C++ | 语句】条件语句(if、switch)、循环语句(while、do while、for、范围for)、跳转语句、try语句块和异常处理

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a;2024-05-02 2…

C++ 继承篇

面向对象语言的三大特性&#xff1a;封装&#xff0c;继承和多态 根据目前学到的知识&#xff0c;对于封装的理解&#xff0c;大致有两层&#xff1a; 将数据和方法封装&#xff0c;不想让外面看到用private/protected修饰&#xff0c;想让外面看到用public修饰类型的行为不满…

C语言自定义类型——枚举

枚举 枚举定义枚举 与 #define使用写一个简易计算器的程序。 枚举定义 格式&#xff1a; enum name(枚举什么类型) {//数据 ... };枚举&#xff0c;顾名思义一 一 列举。 在生活当中有很多可以列举的东西。 如&#xff1a; //电脑桌面上的软件 enum App {QQ ,WeChat,CCtalk,…

厂家自定义 Android Ant编译流程源码分析

0、Ant安装 Windows下安装Ant&#xff1a; ant 官网可下载 http://ant.apache.org ant 环境配置&#xff1a; 解压ant的包到本地目录。 在环境变量中设置ANT_HOME&#xff0c;值为你的安装目录。 把ANT_HOME/bin加到你系统环境的path。 Ubuntu下安装Ant&#xff1a; sudo apt…

AcWing 4993 FEB

4993. FEB - AcWing题库 大佬亲笔 将原串分成三段&#xff1a; FFF|E.....B|FFF 先合并中间段&#xff0c;再合并两边的段 #include <iostream> #include <cstring> #include <algorithm> #include <string> #include <queue&g…

【热门话题】如何通过AI技术提升内容生产的效率与质量

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 如何通过AI技术提升内容生产的效率与质量引言一、自然语言处理&#xff08;NLP&…