当前位置: 首页 > news >正文

设计模式之创建型模式

 创建型模式:创建对象的机制,从所需要实例化的对象中解耦。主要分成了五种设计模式,即工厂方法、抽象工厂、生成器、原型、单例。

文章目录

  • 工厂方法
  • 抽象工厂
  • 生成器
  • 原型
  • 单例

工厂方法

 问题:一个物流公司最初只使用卡车运输,现需要增加轮船运输业务。目前的程序代码与卡车关联。
 解决方法:定义一个用于创建对象的接口,让子类决定实例化哪一个类。FactoryMethod使一个类的实例化延迟到其子类。
在这里插入图片描述
uml类图
测试代码:

#include <iostream>
using namespace std;//产品的接口
class Transport
{
public:virtual ~Transport() {};virtual void deliver() const = 0;
};//产品A
class Truck :public Transport
{
public:void deliver() const override{std::cout << "卡车运输中ing\n";}
};//产品B
class Ship :public Transport
{
public:void deliver() const override{std::cout << "轮船运输中ing\n";}
};//创造者
class Logistics
{
public:virtual ~Logistics() {};virtual Transport* factoryMethod() const = 0;void doSomething(){Transport* transport = factoryMethod();transport->deliver();delete transport;}
};//具体的创造者A
class TruckLogistis :public Logistics {
public:virtual ~TruckLogistis() {}virtual Transport* factoryMethod() const override {return new Truck();}
};
//具体的创造者B
class ShipLogistis :public Logistics {
public:virtual ~ShipLogistis() {}virtual Transport* factoryMethod() const override {return new Ship();}
};int main()
{Logistics* truckLogistics = new TruckLogistis();Logistics* shipLogistics = new ShipLogistis();truckLogistics->doSomething();truckLogistics->doSomething();shipLogistics->doSomething();shipLogistics->doSomething();shipLogistics->doSomething();delete truckLogistics;delete shipLogistics;return 0;
}

在这里插入图片描述
缺点:应用工厂方法模式需要引入许多新的子类,代码可能会因此 变得更复杂。最好的情况是将该模式引入创建者类的现有层次结构中。

抽象工厂

 问题:家具店里有沙发、椅子、茶几等产品。产品有不同风格,如现代、北欧、工业。希望确保客户收到的产品风格统一,并可以方便的添加新产品和风格。
 解决方案:提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
在这里插入图片描述
uml图
测试代码:

#include <iostream>
using namespace std;class Chair
{
public:virtual~Chair() {};virtual void sitOn() const = 0;
};class ModernChair :public Chair
{
public:virtual~ModernChair() {};void sitOn() const override{std::cout << "可以被坐下的ModernChair\n";}
};class ChineseChair :public Chair
{
public:virtual~ChineseChair() {};void sitOn() const override{std::cout << "可以被坐下的ChineseChair\n";}
};class Table
{
public:virtual~Table() {};virtual void putOn() const = 0;
};class ModernTable :public Table
{
public:virtual~ModernTable() {};void putOn() const override{std::cout << "ModernTable可以放东西\n";}
};class ChineseTable :public Table
{
public:virtual~ChineseTable() {};void putOn() const override{std::cout << "ChineseTable可以放东西\n";}
};class FurnitureFacotry {//抽象工厂
public:virtual Chair* createChair() const = 0;virtual Table* createTable() const = 0;
};class ModernStyleFactory :public FurnitureFacotry {
public:Chair* createChair() const override {return new ModernChair();}Table* createTable() const override {return new ModernTable();}
};class ChineseStyleFactory :public FurnitureFacotry {
public:Chair* createChair() const override {return new ChineseChair();}Table* createTable() const override {return new ChineseTable();}
};class Client
{
private:FurnitureFacotry* m_furniturefactory;
public:Client(FurnitureFacotry* furniturefactory){setFactory(furniturefactory);}void buyFurniture(){Chair* chair = m_furniturefactory->createChair();Table* table = m_furniturefactory->createTable();chair->sitOn();table->putOn();delete chair;delete table;}void setFactory(FurnitureFacotry* furniturefactory){m_furniturefactory = furniturefactory;}
};
int main()
{ModernStyleFactory modernFactory;Client client(&modernFactory);client.buyFurniture();ChineseStyleFactory chineseFactory;client.setFactory(&chineseFactory);client.buyFurniture();return 0;
}

在这里插入图片描述
缺点:在产品族中扩展新的产品需要修改抽象工厂的接口代码。

生成器

 问题:1、构造一个房屋,需要考虑是否有车库,游泳池,花园,雕塑等,需要对诸多成员变量进行初始化工作。都写在构造函数里?每种可能都创建一个新的类?2、相同的步骤需要能够产生不同的产品,例如使用木头和玻璃盖出来的是普通住房。用黄金和水晶建造出来的是宫殿。
 解决方案:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。即将对象构造代码从产品类中抽取出来,并将其放在一个名为Builder的独立对象中。
在这里插入图片描述
uml类图
测试代码:

#include <iostream>
#include <vector>
#include <string>using namespace std;class SimpleHouse
{
public:std::vector<std::string> m_parts;void printParts() const{std::cout << "SimpleHouse 包括:\n";for (int i = 0; i < m_parts.size(); i++){std::cout << m_parts[i] << std::endl;}std::cout << "-----------------------------------\n";}
};class Builder
{
public:virtual ~Builder() {};virtual void reset() = 0;virtual void makeBaseHouse() = 0;virtual void makeGarage() = 0;virtual void makePool() = 0;
};class SimpleHouseBuilder :public Builder
{
private:SimpleHouse* m_sh;
public:SimpleHouseBuilder(){reset();}~SimpleHouseBuilder(){if (m_sh)delete m_sh;}void reset() override{m_sh = new SimpleHouse;}void makeBaseHouse() override{m_sh->m_parts.push_back("BaseHouse");}void makeGarage() override{m_sh->m_parts.push_back("Garage");}void makePool() override{m_sh->m_parts.push_back("Pool");}SimpleHouse* getResult() {SimpleHouse* result = m_sh;reset();return result;}
};
//主管:负责流程
class Director 
{
private:Builder* m_builder;
public:void setBuilder(Builder* builder){m_builder = builder;}void makeSimpleHouse() {m_builder->makeBaseHouse();m_builder->makeGarage();}void makeFullFuncHouse() {m_builder->makeBaseHouse();m_builder->makeGarage();m_builder->makePool();}
};void client(Director* director)
{std::cout << "客户自己设计流程.." << std::endl;SimpleHouseBuilder* shb = new SimpleHouseBuilder;shb->makeBaseHouse();shb->makeGarage();SimpleHouse* sh = shb->getResult();sh->printParts();delete sh;std::cout << "主管负责设计流程.." << std::endl;director->setBuilder(shb);director->makeFullFuncHouse();sh = shb->getResult();sh->printParts();delete sh;delete shb;
}int main()
{Director dir;client(&dir);return 0;
}

在这里插入图片描述
 缺点:如果产品之间的差异性很大,则不适合使用建造者模式,使用范围受到一定的限制。

原型

 问题:希望复制一个状态完全相同的对象。首先,新建一个相同类的对象。 然后,复制所有成员变量。 但是,有时候不知道具体类型,而且成员变量可能是私有的。(从外部复制对象并非总是可行的)
 解决方案:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。即复制已有对象,而无需使代码依赖他们所属的类。
在这里插入图片描述
uml类图
测试代码:

#include <iostream>
#include <unordered_map>
using namespace std;enum Type
{ROBOT_CAT = 0,ROBOT_DOG
};class Robot
{
protected:std::string m_prototype_name = "";float m_stateOfCharge = 0;
public:virtual ~Robot() {};Robot(std::string prototype_name) :m_prototype_name(prototype_name) {}virtual Robot* clone()const = 0;virtual void setStateOfCharge(float) = 0;
};class RobotCat :public Robot
{
private:float m_catValue;
public:RobotCat(std::string name,float value) :Robot(name), m_catValue(value) {}Robot* clone()const{return new RobotCat(*this);}void setStateOfCharge(float value){m_stateOfCharge = value;std::cout << "--" << m_prototype_name << " 当前电量:" << m_stateOfCharge<< ",m_CatValue:" << m_catValue << std::endl;}
};class RobotDog :public Robot
{
private:float m_dogValue;
public:RobotDog(std::string name,float value) :Robot(name), m_dogValue(value) {}Robot* clone()const{return new RobotDog(*this);}void setStateOfCharge(float value){m_stateOfCharge = value;std::cout << "--" << m_prototype_name << " 当前电量:" << m_stateOfCharge<< ",m_dogValue:" << m_dogValue << std::endl;}
};class cloneFactory
{
private:std::unordered_map<Type, Robot*> m_prototypes;
public:cloneFactory(){m_prototypes[ROBOT_CAT] = new RobotCat("机器猫", 5.0);m_prototypes[ROBOT_DOG] = new RobotCat("机器狗", 8.0);}~cloneFactory(){delete m_prototypes[ROBOT_CAT];delete m_prototypes[ROBOT_DOG];}Robot* createRobot(Type type) {return m_prototypes[type]->clone();}
};void client(cloneFactory&rf)
{std::cout << "克隆机器猫:\n";Robot* cloneRobot = rf.createRobot(ROBOT_CAT);cloneRobot->setStateOfCharge(90);delete cloneRobot;cloneRobot = rf.createRobot(ROBOT_CAT);cloneRobot->setStateOfCharge(80);delete cloneRobot;std::cout << "克隆机器狗:\n";cloneRobot = rf.createRobot(ROBOT_DOG);cloneRobot->setStateOfCharge(75);delete cloneRobot;
}int main()
{cloneFactory rf;client(rf);return 0;
}

在这里插入图片描述
缺点:克隆包含循环引用的复杂对象可能会非常麻烦。

单例

 问题:对于一些类来说,只有一个实例是很重要的。例如数据库或其共享资源的访问权限。并且这个实例需要易于被访问。
 解决方案:保证一个类只有一个实例,并提供一个访问它的全局访问点。
在这里插入图片描述

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;class Singleton
{
private:Singleton(std::string value) :m_value(value) {};~Singleton() {};std::string m_value;
public:Singleton(Singleton& other) = delete;void operator=(const Singleton&) = delete;std::string value() const { return m_value; }static Singleton* getInstance(const std::string& value);
private:static Singleton* m_instance;static std::mutex m_mutex;
};std::mutex Singleton::m_mutex;
Singleton* Singleton::m_instance = nullptr;Singleton* Singleton::getInstance(const std::string& value)
{std::lock_guard<std::mutex> lock(m_mutex);if (m_instance == nullptr) {m_instance = new Singleton(value);}return m_instance;//static Singleton* instance = new Singleton(value);//return instance;
}void cat()
{Singleton* singleton = Singleton::getInstance("Cat");std::cout << singleton->value() << '\n';
}void dog()
{Singleton* singleton = Singleton::getInstance("Dog");std::cout << singleton->value() << '\n';
}int main()
{std::thread t1(cat);std::thread t2(dog);t1.join();t2.join();return 0;
}

在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 不同的子序列-java
  • UE4_动画基础_角色的缩放
  • conda创建虚拟环境太慢,Collecting package metadata (current_repodata.json): failed
  • SQLite数据库的性能问题并不是单纯地由数据量的大小决定的,而是受到多种因素的综合影响。以下是一些可能导致SQLite性能问题的因素
  • MongoDB聚合运算符:$map
  • AJAX —— 学习(一)
  • Leetcode56_合并区间
  • 21. 面试指导-高频面试题详解
  • 一次部署,多处运行:Docker容器化开发
  • Java 处理Mysql获取树形的数据
  • SpringBoot多级多模块聚合项目下maven打包报‘packaging‘ with value ‘jar‘ is invalid.
  • 图书馆自助借书机怎么借书
  • Bash相关
  • Mysql安装(命令方式安装)
  • 基于深度学习的电动自行车头盔佩戴检测系统
  • 【干货分享】SpringCloud微服务架构分布式组件如何共享session对象
  • 【技术性】Search知识
  • 3.7、@ResponseBody 和 @RestController
  • HTML5新特性总结
  • Java 内存分配及垃圾回收机制初探
  • Java方法详解
  • JAVA之继承和多态
  • Joomla 2.x, 3.x useful code cheatsheet
  • mongodb--安装和初步使用教程
  • Python利用正则抓取网页内容保存到本地
  • SAP云平台运行环境Cloud Foundry和Neo的区别
  • Travix是如何部署应用程序到Kubernetes上的
  • use Google search engine
  • webpack入门学习手记(二)
  • 经典排序算法及其 Java 实现
  • 理清楚Vue的结构
  • 移动端 h5开发相关内容总结(三)
  • 掌握面试——弹出框的实现(一道题中包含布局/js设计模式)
  • puppet连载22:define用法
  • 移动端高清、多屏适配方案
  • (编译到47%失败)to be deleted
  • (附源码)spring boot基于小程序酒店疫情系统 毕业设计 091931
  • (附源码)springboot掌上博客系统 毕业设计063131
  • (附源码)springboot助农电商系统 毕业设计 081919
  • (实测可用)(3)Git的使用——RT Thread Stdio添加的软件包,github与gitee冲突造成无法上传文件到gitee
  • (学习日记)2024.01.09
  • (转)nsfocus-绿盟科技笔试题目
  • (转)淘淘商城系列——使用Spring来管理Redis单机版和集群版
  • (转载)Linux网络编程入门
  • (自用)仿写程序
  • .NET 4.0网络开发入门之旅-- 我在“网” 中央(下)
  • .net core 3.0 linux,.NET Core 3.0 的新增功能
  • .net core使用RPC方式进行高效的HTTP服务访问
  • .NET Remoting Basic(10)-创建不同宿主的客户端与服务器端
  • .net 怎么循环得到数组里的值_关于js数组
  • .NET开源全面方便的第三方登录组件集合 - MrHuo.OAuth
  • .Net小白的大学四年,内含面经
  • /deep/和 >>>以及 ::v-deep 三者的区别
  • [ 常用工具篇 ] AntSword 蚁剑安装及使用详解
  • [BZOJ3223]文艺平衡树