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