创建型模式:创建对象的机制,从所需要实例化的对象中解耦。主要分成了五种设计模式,即工厂方法、抽象工厂、生成器、原型、单例。
文章目录
- 工厂方法
- 抽象工厂
- 生成器
- 原型
- 单例
工厂方法
问题:一个物流公司最初只使用卡车运输,现需要增加轮船运输业务。目前的程序代码与卡车关联。
解决方法:定义一个用于创建对象的接口,让子类决定实例化哪一个类。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;
}