C++设计模式
享元模式
所谓享元模式是指运用共享技术有效地支持大量细粒度的对象。在有大量对象时,把其中共同的部分抽象出来,如果有相同的业务请求,直接返回内存中已有的对象,避免重新创建。
享元模式的优点:
1.它可以极大减少内存中对象的数量,使得相同对象和相似对象在内存中只存在一份。
2.享元模式的外部状态相对独立,而且不会影响其内部状态,从而使享元对象可以在不同的环境中被共享。
享元模式的缺点:
1.享元模式时的系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。
2.为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间更长。
享元模式的适用场景:
1.一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量浪费。
2.对象的大部分状态都可以外部化,可以将这些外部状态传到对象中。
3.使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费资源,因此,应当在多次重复使用享元对象
时才值得使用享元模式。
例程:
#include <iostream>
#include <map>
#include <memory>
using namespace std;
//抽象享元类,提供享元类外部接口。
class AbstractConsumer
{
public:
virtual ~AbstractConsumer(){}
virtual void setArticle(const string&) = 0;
virtual const string& article() = 0;
};
//具体的享元类
class Consumer : public AbstractConsumer
{
public:
Consumer(const string& strName) : m_user(strName){}
~Consumer()
{
cout << " ~Consumer()" << endl;
}
void setArticle(const string& info) override
{
m_article = info;
}
const string& article() override
{
return m_article;
}
private:
string m_user;
string m_article;
};
//享元工厂类
class Trusteeship
{
public:
~Trusteeship()
{
m_consumerMap.clear();
}
void hosting(const string& user, const string& article)
{
if(m_consumerMap.count(user))
{
cout << "A customer named " << user.data() << " already exists" << endl;
Consumer* consumer = m_consumerMap.at(user).get();
consumer->setArticle(article);
}
else
{
shared_ptr<Consumer> consumer(new Consumer(user));
consumer.get()->setArticle(article);
m_consumerMap.insert(pair<string, shared_ptr<Consumer>>(user, consumer));
}
}
void display()
{
map<string, shared_ptr<Consumer>>::iterator iter = m_consumerMap.begin();
for(; iter != m_consumerMap.end(); iter++)
{
cout << iter->first.data() << " : "<< iter->second.get()->article().data() << endl;
}
}
private:
map<string, shared_ptr<Consumer>> m_consumerMap;
};
int main()
{
Trusteeship* ts = new Trusteeship;
ts->hosting("zhangsan", "computer");
ts->hosting("lisi", "phone");
ts->hosting("wangwu", "watch");
ts->display();
ts->hosting("zhangsan", "TT");
ts->hosting("lisi", "TT");
ts->hosting("wangwu", "TT");
ts->display();
delete ts;
ts = nullptr;
return 0;
}
工厂模式
工厂模式是我们日常最常见的一种创建型设计模式了,它提供了一种创建对象的最佳方式,在工厂模式中,我们在创建对象时,不会在客户端暴露创建逻辑,并且使用一个共同的接口来指向新创建的对象。
工厂模式的优点:
1:一个调用者想创建一个对象,只要知道其名称就可以了。
2:扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
3:屏蔽产品的具体实现,调用者只关心产品的接口。
工厂模式的缺点:
1.每增加一个产品时,都需要增加一个产品具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度
上增加了系统的复杂度,同时也增加了系统具体类的依赖,这并不是什么好事儿。
适用场景:
1.工厂模式的目的是为了实现解耦,将对象的创建和使用分开,即应用程序将对象的创建和初始化职责交给工厂
对象。若一个对象A想要调用对象B时,如果直接通过new关键字来创建一个B实例,然后调用B实例,这样做的
不好处是,当需求变更,要将B实例换成C实例时,则需要修改所有new了该实例的方法。
2.降低代码重复。如果对象B的创建过程比较复杂,并且很多地方都用到了,那么很可能出现很多重复的代码,
通过统一将创建对象B的代码放到工厂里面统一管理,可以减少代码的重复率,同时也方便维护。相比于构造
函数来说,复杂的初始化,会使得构造函数非常的复杂。由于创建过程都由工厂统一的管理,有利于当业务
发生变化之后的修改
3.工厂模式将创建和使用分离,使用者不需要知道具体的创建过程,只需要使用即可。
4.类本身有很多子类,并且经常性发生变化。创建对象需要大量重复的代码。创建对象需要访问某些信息,
而这些信息不应该包含在复合类中。创建对象的生命周期必须集中管理,以保证在整个程序中具有一致的行为。
工厂模式分类:
工厂模式分为简单工厂模式、工厂方法模式、抽象工厂模式三种。
下边是三种工厂模式的具体实现。
一、简单工厂模式:主要特点是需要在工厂类中做出判断,从而创造相应的产品,当增加新产品时,需要修改工厂类。
typedef enum
{
T80 = 1,
T99
}TankType;
class Tank
{
public:
virtual void message() = 0;
};
class Tank80:public Tank
{
public:
void message()
{
cout << "Tank80" << endl;
}
};
class Tank99:public Tank
{
public:
void message()
{
cout << "Tank99" << endl;
}
};
class TankFactory
{
public:
Tank* createTank(TankType type)
{
switch(type)
{
case 1:
return new Tank80();
case 2:
return new Tank99();
default:
return NULL;
}
}
};
二、工厂方法模式:是指定义一个创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到其子类。
class Tank
{
public:
virtual void message() = 0;
};
class Tank80:public Tank
{
public:
void message()
{
cout << "Tank80" << endl;
}
};
class Tank99:public Tank
{
public:
void message()
{
cout << "Tank99" << endl;
}
};
class TankFactory
{
public:
virtual Tank* createTank() = 0;
};
class Tank80Factory:public TankFactory
{
public:
Tank* createTank()
{
return new Tank80();
}
};
class Tank99Factory:public TankFactory
{
public:
Tank* createTank()
{
return new Tank99();
}
};
三、抽象工厂模式:提供一个创建一系列相关或相互依赖的对象接口,而无需指定它们的具体类。
class Tank
{
public:
virtual void message() = 0;
};
class Tank80:public Tank
{
public:
void message()
{
cout << "Tank80" << endl;
}
};
class Tank99:public Tank
{
public:
void message()
{
cout << "Tank99" << endl;
}
};
class Plain
{
public:
virtual void message() = 0;
};
class Plain80: public Plain
{
public:
void message()
{
cout << "Plain80" << endl;
}
};
class Plain99: public Plain
{
public:
void message()
{
cout << "Plain99" << endl;
}
};
class Factory
{
public:
virtual Tank* createTank() = 0;
virtual Plain* createPlain() = 0;
};
class Factory80:public Factory
{
public:
Tank* createTank()
{
return new Tank80();
}
Plain* createPlain()
{
return new Plain80();
}
};
class Factory99:public Factory
{
public:
Tank* createTank()
{
return new Tank99();
}
Plain* createPlain()
{
return new Plain99();
}
};
代理模式
所谓代理模式是指为其他对象提供一种代理以控制对这个对象的访问。
代理模式的优点:
1、代理模式能将代理对象和真正被调用的对象分离,在一定程度上降低了系统的耦合度。
2、代理模式在客户端和目标对象之间起到一个中介的作用,这样可以起到保护目标对象的作用,代理对象
也可以在目标对象调用之前,进行其他的操作。
代理模式的缺点:
1、在客户端和目标对象之间增加一个代理对象,会造成请求速度变慢。
2、增加了系统的复杂度。
代理模式的适用场景:
1、远程代理,也就是为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间
的事实。
2、虚拟代理,根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的对象。
3、安全代理,用来控制真实对象访问时的权限。
4、智能指引,当调用目标对象时,代理可以处理其他的一些操作。
以下是代码实现:
class Gril
{
public:
Gril(string name = "gril"):m_string(name){}
string getName()
{
return m_string;
}
private:
string m_string;
};
class Profession
{
public:
virtual ~Profession(){}
virtual void profess() = 0;
};
class YoungMan:public Profession
{
public:
YoungMan(Gril gril):m_gril(gril){}
void profess()
{
cout << "Young man love " << m_gril.getName().data() << endl;
}
private:
Gril m_gril;
};
class ManProxy:public Profession
{
public:
ManProxy(Gril gril):m_man(new YoungMan(gril)){}
void profess()
{
cout << "I am Proxy" << endl;
m_man->profess();
}
private:
YoungMan* m_man;
};
int main(int argc, char *argv[])
{
Gril gril("hei");
Profession* proxy = new ManProxy(gril);
proxy->profess();
delete proxy;
return 0;
}