设计模式 创建型模式 单例工厂等
单例模式
确保对象的唯一性.
饿汉模式,提前创建好, 比如静态定义.即在对象创建前,该对象就创建好了, 但是对象特别大时,可能耗费时间,不是很有必要.
懒汉模式,第 1 次调用时,才 new.下面是一个经典的双重check锁定+饿汉
的单例:
//.h
public
static timerRunner* getInstance(void);
private:
static pthread_mutex_t mutex;
static timerRunner* m_instance;
...
//.c
pthread_mutex_t timerRunner::mutex = PTHREAD_MUTEX_INITIALIZER;
timerRunner* timerRunner::m_instance = NULL;
timerRunner* timerRunner::getInstance(void)
{
if(NULL == m_instance) {
pthread_mutex_lock(&mutex);
if(NULL == m_instance) {
m_instance = new timerRunner(128);
}
pthread_mutex_unlock(&mutex);
}
return m_instance;
}
还有一种更好的单例模式,Initialization on Demand Holder(IoDH)
实现方式是单例类里,再增加一个静态内部类
,,静态内部类创建单例对象再返回;好在哪里?并不太明白.
简单工厂
把 new productA, new productB…封装在一个 factory 对象里,由 factory 统一管理对象的 new,使用者不关心怎么 new 出对象;
对外的接口类似:
proFactory::get_product(string p)
{
if p == string("A")
return new productA();
if p == string("B")
return new productB();
...
}
factory = new proFactory();
productA = factory.get_product("A");
productA = factory.get_product("B");
...
当然 get_product 也可以是静态方法.
productA = proFactory().get_product("A");
productB = proFactory().get_product("B");
...
在实际要使用 product 的类里,注意对象的职责问题
, 即对象的创建和对象的使用分离,尽量不要放在一个类里,否则,当对象需要改变时,又得修改类,违背开闭原则.
对象的职责是指: 谁创建对象, 对象本身可以做什么, 谁使用对象
经典的使用简单工厂的例子:
class product {
virtual const string & name() = 0
}
class productA : public Product {
// 实现自己的name
};
class productB : public Product {
// 实现自己的name
};
class Store {
private:
Product * mp;
public:
//不是具体的product,而是用product的基类, 结合工厂模式
void set_product(string name) {
mp = proFactory().get_product(name);
}
show_product_name() {
return mp->name();
}
};
工厂方法 (多态工厂模式)
如果简单工厂的工厂
本身复杂,而且工厂创建的对象也很多,很复杂,那么再次将工厂抽象
掉是个很自然的想法.每一个或者一类的产品的创建对应一个抽象工厂的派生工厂.
class foodFactory : public Factory {...}
class clothFactory : public Factory {...}
class Store: public {
Factory factory;
public:
void produce() {
//food工厂new出fish
factory = foodFactory();
fish = factory.get_product("fish");
//cloth工厂new出pants
factory = clothFactory();
pants = factory.get_product("pants");
}
}
...
进一步的,将实际的工厂
,产品
的具体名字配置到配置文件里, 灵活性就大大增加了.
从普通角度,自然可以读取文件,用if...else
提前把代码写好,但是一旦新增工厂,还得改代码.
java 里的反射
机制, 从类名创建出对象, 只用新增一个工厂类以及实现就好了,符合开闭原则
.
重载的工厂方法
重载实现的更多的生产对象的生产方法(就是 get_product 的不同参数),满足更多的需求.
class foodFactory : public Factory {
public:
Product * get_product(string name);
//重载的工厂方法
Product * get_product(string path);
Product * get_product(date date);
}
抽象工厂模式
可以理解为工厂的组合,每个工厂对应具体的产品,不同的工厂实现,就是不同的组合,也就是不同的产品族.
class peopleFactory {
virtual Product* get_cloth() = 0;
virtual Product* get_food() = 0;
virtual Product* get_glass() = 0;
}
class AisaPeopleFactory : public peopleFactory {
Product* get_cloth() {return new AisaCloth();}
Product* get_food() {return new AisaFood();}
Product* get_glass() {return new Aisaglass();}
}
class AfricaPeopleFactory : public peopleFactory {
Product* get_cloth() {return new AfricaCloth();}
Product* get_food() {return new AfricaFood();}
Product* get_glass() {return new AfricaGlass();}
}
切换一个抽象工厂时,就切换了一个产品族.
书上的是讲 UI 换皮肤,也是很生动的例子.
原型模式
就是对象的拷贝,java 里的 clone,类似的 c++里的深拷贝
// = 要求是做了深拷贝实现, 对应java里的Cloneable接口的实现
Object old("some paras");
auto new = old;
皮一点,也可以给自己的类增加一个clone()
方法,实现深拷贝就好.
建造者模式
略