Single-Responsibilitiy Principle(SRP),对一个类而言,应该仅有一个引起它变化的原因。如果存在多于一个动机去改变一个类,那么这个类就具有多于一个的职责,就应该把多余的职责分离出去,再去创建一些类来完成每一个职责。举个例子,一个人身兼数职,而这些事情相关性不大,甚至有冲突,那他就无法很好的解决这些问题职责,应该分到不同的人身上去做。单一职责原则是实现高内聚低耦合的最好方法,没有之一。
Open-Close Principle(OCP),一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。目的就是保证程序的扩展性好,易于维护和升级。开闭原则被称为面向对象设计的基石,实际上,其他原则都可以看作是实现开闭原则的工具和手段。意思就是,软件对扩展应该是开放的,对修改是封闭的,通俗来说就是,开发一个软件时,应该对其进行功能扩展,而在进行这些扩展时,不需要对原来的程序进行修改。好处是,软件可用性非常灵活,扩展性强。需要新的功能时,可以增加新的模块来满足新需求。另外由于原来的模块没有修改,所以不用担心稳定性的问题。
Dependence Inversion Principle(DIP),是一个类与类之间的调用规则。这里的依赖就是代码中的耦合。高层模块不应该依赖底层模块,二者都应该依赖其抽象,抽象不依赖细节,细节应该依赖抽象。接口编程,主要思想就是,如果一个类中的一个成员或者参数成为一个具体的类型,那么这个类就依赖这个具体类型。如果在一个继承结构中,上层类中的一个成员或者参数为一个下层类型,那么就是这个继承结构高层依赖底层,就要尽量面向抽象或者接口编程。举个例子,存在一个Driver类,成员为一个Car对象,还有一个driver()方法,Car对象中有两个方法start()与stop(),显然Driver依赖Car,也就是说Driver类调用了Car类中的方法,但是当增加Driver类对于Bus类的支持时(司机有需要开公交车),就必须更改Driver中的代码,就破坏了开放封闭原则。根本原因在于高层的的Driver类与底层的Car类仅仅的耦合在一起的。解决方法之一就是,对Car类和Bus类进行抽象,引入抽象类Automoble。而Car和Bus则是对Automobile的泛化。经过这样的改造发现,原本的高层依赖底层,变成了高层与底层同时依赖抽象。这就是依赖倒转原则的本质。
Liskov Substitution Principle,子类可以扩展父类的功能,但是不能改变父类原有的功能。在开放封闭原则中,主张“抽象”和“多态”。维持设计的封装性“抽象”是语言提供的功能,“多态”由继承语意实现。因此如何去度量继承关系中的质量?答案是,继承必须明确确保超类(父类)所拥有的性质在子类中仍然成立。在面向对象的思想中,一个对象就是一组状态和一系列行为的组合体。状态是对象的内在特性,行为是对象的外在特性。LSP表述的就是在同一继承体系中的队形应该具有共同的行为特征。
class bird:
color = ''
weight = ''
def eat():
pass
def fly():
print("fly")
class chicken(bird):
def fly():
print("can not fly")
在上述例子中,父类也就是对象鸟有两个行为也就是方法:eat()
和fly()
,在子类chicken中这两个行为也应该成立,但是现实中chicken是不能飞的,因此chicken中的fly()
方法覆盖了父类中的方法,违反了LSP。
Law of Demeter(最小知识原则),一个对象应该对其他对象有最少的了解。通俗来说就是,一个类对自己需要耦合或者调用的类知道的最少,你类内部怎么复杂,我不管,那是你的事,我只知道你有那么多公用的方法,我能调用。迪米特法则不希望类与类之间建立直接的接触。如果真的需要有联系,那么就通过它们的友元类来传达。举例来说,你需要买房子了,现在存在三座合适的楼盘A,B,C,但是你不必直接去楼盘买楼,而是在售楼处去了解情况。这样就减少了你(购房者)与楼盘两个类之间耦合。但是应用迪米特法则很可能会造成一个后果,系统会存在大量的中介类,这些类(如上面的售楼处类)之所以存在是为了传递类之间的相互调用关系,这就一定会程度上增加了系统的复杂度。迪米特法则核心观念就是:类间解耦,弱耦合。
接口隔离原则(Interface Segregation Principle),用于恰当的划分角色和接口,具有两种含义:(1)用户不应该依赖它不需要的借口;(2)类间的依赖关系应该建立在最小的的接口上。将这两个定义概括为一句话:建立单一接口,代替庞大臃肿的接口。通俗来说就是,接口尽量细化,同时保证接口中的方法尽量的少。一个接口中包含太多的行为时,会导致它们与客户端的不正常依赖关系,要做的就是分离接口,从而实现解耦。回到单一职责原则,要求行为分离,接口细化,感觉有些相同。但实际上,单一职责原则要求类与接口的职责单一,注重的是职责,没有要求接口尽量的少。在接口隔离原则中,要求尽量使用多个专门的接口。专门的接口也就是提供给多个模块的接口,提供给几个模块就应该有几个接口,而不是建立一个臃肿庞大的接口,所有的模块都可以访问。但是接口的设计是有限度的。接口的设计粒度越小系统越灵活,这是事实,但是接口太多这也就使得结构复杂,维护难度大。因此实际中,怎样把握就靠开发的经验和常识了。
先看一段代码,设计一个计算器:
#include
using namespace std;
enum op {
ADD = 1,
SUB = 2,
MUL = 3,
DIV = 4,
};
// 运算类
class Operation {
public:
Operation() {
m_NumA = 0;
m_NumB = 0;
m_Result = 0;
}
~Operation() {}
void SetValue(double numA, double numB) {
m_NumA = numA;
m_NumB = numB;
}
double GetNumA() {
return m_NumA;
}
double GetNumB() {
return m_NumB;
}
virtual double GetResult() {
return m_Result;
}
private:
double m_NumA;
double m_NumB;
double m_Result;
};
// 加法类,继承运算类
class Add : public Operation {
public:
double GetResult() {
double numA = GetNumA();
double numB = GetNumB();
return (numA + numB);
}
};
// 减法类,继承运算类
class Sub : public Operation {
public:
double GetResult() {
double numA = GetNumA();
double numB = GetNumB();
return (numA - numB);
}
};
// 乘法类,继承运算类
class Mul : public Operation {
public:
double GetResult() {
double numA = GetNumA();
double numB = GetNumB();
return (numA * numB);
}
};
// 除法类,继承运算类
class Div : public Operation {
public:
double GetResult() {
double numA = GetNumA();
double numB = GetNumB();
if (numB == 0)
throw numB;
return (numA / numB);
}
};
// 简单运算工厂类
class OperationFactory {
public:
OperationFactory() {}
~OperationFactory() {}
static Operation* createOperate(op operate) {
Operation *oper;
switch(operate) {
case ADD:
oper = new Add();
break;
case SUB:
oper = new Sub();
break;
case MUL:
oper = new Mul();
break;
case DIV:
oper = new Div();
break;
}
return oper;
}
};
int main() {
OperationFactory *factor = new OperationFactory; // 生产计算器的工厂
Operation *oper = factor->createOperate(ADD); // 生产一个加法计算器
oper->SetValue(1, 2); // 调用父类函数
double ret = oper->GetResult(); // 虚函数,调用子类函数
cout << "result: " << ret << endl;
return 0;
}
运行结果:result: 3
。如果需要更改加法算法,只需要更改 Add 类就可以。如果要增加其他运算,比如平方根、正弦、自然对数等,只要增加相应的运算子类和修改运算类工厂(在 switch 中增加分支)即可。
计算器工厂是工厂,负责创建所有实例;计算器是抽象产品,所有具体产品的父类,负责描述所有实例所有的公共接口;加法计算器是具体产品,最终创建的具体产品。
策略模式是一种定义一系列算法的方法,从概念上看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少各种算法类与使用算法类之间的耦合(DPE)。策略模式的 Strategy 类层次为 Context 定义了一系列的可供重用的算法或行为。
设计一个商场收费软件,支持正常收费、打折收费、满减收费等功能:
#include
using namespace std;
// 现金收费抽象类
class CashSuper {
public:
// 抽象方法,收取现金,参数为原价,返回当前价
virtual double acceptCash(double money) = 0;
};
// 正常收费子类
class CashNormal : public CashSuper {
public:
double acceptCash(double money) {
return money; // 正常收费,返回原价
}
};
// 打折收费子类
class CashRebate : public CashSuper {
public:
CashRebate(double rebate) { // 初始时必须传入折扣率
moneyRebate = rebate;
}
double acceptCash(double money) {
return (money * moneyRebate);
}
private:
double moneyRebate; // 折扣率
};
// 返利收费子类
class CashReturn : public CashSuper {
public:
// 满Condition,返Return
CashReturn(double Condition, double Return) {
m_condition = Condition;
m_return = Return;
}
double acceptCash(double money) {
double result = money;
if (money >= m_condition) {
result = money - (money / m_condition) * m_return;
}
return result;
}
private:
double m_condition;
double m_return;
};
class CashContext {
public:
CashContext(CashSuper *csuper) { // 传入具体的收费策略
cs = csuper;
}
double GetResult(double money) {
// 根据不同的收费策略,获得计算结果
return cs->acceptCash(money);
}
private:
CashSuper *cs; // 声明一个CashSuper对象
};
int main() {
CashContext *cc = new CashContext(new CashReturn(300, 100)); // 满300减100
double total = cc->GetResult(900); // 消费900
cout << "total: " << total << endl; // 需要支付
return 0;
}
运行结果:total: 600
。对于像商场这种经常更改打折额度和返利额度的,如果用简单工厂模式,每次都要更改这个工厂,这不是最好的方法。面对算法经常变动,应该用策略模式。
设计一个给人模拟搭配不同服饰的程序,可以给人换各种各样的衣服裤子:
#include
using namespace std;
// Component 类
//class Component {
//public:
//virtual void Show() = 0;
//};
// 穿衣基类(ConcreteComponent)
class CDress /*: public Component*/ {
public:
virtual ~CDress() {}
virtual void Show() {
cout << "装扮的人。" << endl;
}
};
// 装饰类基类(Decorator)
class CFinery : public CDress {
public:
CFinery() : m_Dress(NULL) {}
virtual ~CFinery() {}
void Decorate(CDress *dress) {
m_Dress = dress;
}
void Show() {
if (m_Dress) {
m_Dress->Show();
}
}
private:
CDress *m_Dress;
};
// 具体服饰类(ConcreteDecorator)
class CTShirts : public CFinery {
public:
virtual ~CTShirts() {}
void Show() {
cout << "T恤 ";
CFinery::Show();
}
};
class CBigTrouser : public CFinery {
public:
virtual ~CBigTrouser() {}
void Show() {
cout << "垮裤 ";
CFinery::Show();
}
};
class CSneakers : public CFinery {
public:
virtual ~CSneakers() {}
void Show() {
cout << "运动鞋 ";
CFinery::Show();
}
};
class CTie : public CFinery {
public:
void Show() {
cout << "领带 ";
CFinery::Show();
}
};
int main(int argc, char const *argv[]) {
CDress dress;
CSneakers sneakers;
CBigTrouser bigtruser;
CTShirts tshirts;
CTie tie;
// 装饰过程
sneakers.Decorate(&dress);
bigtruser.Decorate(&sneakers);
tshirts.Decorate(&bigtruser);
tie.Decorate(&tshirts);
tie.Show();
return 0;
}
运行结果:领带 T恤 垮裤 运动鞋 装扮的人。
通过装饰过程能够看出,tie 对象装饰了 tshirts 对象,所以 tie 调用 Show()
函数时会调用 tshirts 的 Show()
函数,tshirts 又装饰了 bigtruser 对象,这时 tshirts 又会调用 bigtruser 的 Show()
函数。有点类似递归,也有点类似链表的味道,递归须要有一个终结者,所以最后被装饰的对象 dress 是不再有装饰对象的。同一时候,假设不喜欢这套打扮风格了,要把T恤换成衬衫,这时仅仅要新增一个衬衫装饰类 CShirt ,然后把 tie 的装饰对象换成 CShirt 就可以。这里可见,使用了装饰模式后,换衣服都方便灵活多了。装饰模式适合在原有功能上添加了新功能,可是新功能被调用前/后仍须要调用原有功能的情况,特别适合功能一层一层的扩展,同一时候保持旧有功能的正常调用的场景。
如果只有一个 ConcreteComponent 类而没有抽象的 Component 类,那么 Decorator 可以是 ConcreteComponent 的一个子类。同样的道理,如果只有一个 ConcreteDecorator 类,那么就没有必要建立一个单独的 Decorator 类,而可以把 Decorator 和 ConcreteDecorator 的责任合并成一个类。
先看一段代码,追求者通过代理向娇娇送礼物:
#include
using namespace std;
class GiveGift {
public:
virtual void GiveDolls() = 0;
virtual void GiveFlowers() = 0;
virtual void GiveChocolate() = 0;
};
// 追求者类
class Pursuit : public GiveGift {
public:
Pursuit(string mmName) {
m_mmName = mmName;
}
void GiveDolls() {
cout << m_mmName << " give you a doll" << endl;
}
void GiveFlowers() {
cout << m_mmName << " give you a flower" << endl;
}
void GiveChocolate() {
cout << m_mmName << " give you a chocolate" << endl;
}
private:
string m_mmName;
};
// 代理类
class Proxy : public GiveGift {
public:
Proxy(string mmName) {
gg = new Pursuit(mmName);
}
void GiveDolls() {
gg->GiveDolls();
}
void GiveFlowers() {
gg->GiveFlowers();
}
void GiveChocolate() {
gg->GiveChocolate();
}
private:
Pursuit *gg;
};
int main(int argc, char const *argv[]) {
Proxy *proxy = new Proxy("jiaojiao");
proxy->GiveDolls();
proxy->GiveFlowers();
proxy->GiveChocolate();
delete proxy;
proxy = NULL;
return 0;
}
代理模式使用场合:(1)远程代理,为一个对象在不同的地址空间提供局部代理,隐藏一个对象存在于不同地址空间的事实;(2)虚拟代理,根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真是对象;(3)安全代理,用来控制真实对象访问时的权限;(4)智能指引,当调用真实对象时,代理处理另一些事。
工厂方法模式(Factory Method),定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法是一个类的实例化延迟到其子类。包含的角色:(1)抽象工厂;(2)具体工厂;(3)抽象产品;(4)具体产品。优势:(1)工厂方法模式是对简单工厂模式的稍微的改进,工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际工作推迟到子类中;(2)与简单工厂模式相比,制造产品的工厂类不再只有一个,而是每种具体产品类都对应一个生产它的具体工厂类,而这些具体工厂类的共同特征再被提取出来形成一个抽象产品类,这些具体产品类都继承自这个抽象产品类;(3)当需要增加一种产品的时候,需要做的是:增加一种继承自抽象产品的具体产品类,增加一种继承在抽象工厂的具体工厂类,更改客户端,而不需要在简单工厂模式中那样更改工厂内的switch。
看一段代码,设计雷锋工厂:
#include
using namespace std;
// 抽象产品类:雷锋
class Leifeng {
public:
virtual void Sweep() {
cout << "扫地" << endl;
}
virtual void Wash() {
cout << "洗衣" << endl;
}
virtual void BuyRice() {
cout << "买米" << endl;
}
};
// 下面是两个具体产品类
// 学生雷锋
class Undergraduate : public Leifeng {
public:
void Sweep() {
cout << "学生-扫地" << endl;
}
void Wash() {
cout << "学生-洗衣" << endl;
}
void BuyRice() {
cout << "学生-买米" << endl;
}
};
// 志愿者雷锋
class Volunteer : public Leifeng {
public:
void Sweep() {
cout << "志愿者-扫地" << endl;
}
void Wash() {
cout << "志愿者-洗衣" << endl;
}
void BuyRice() {
cout << "志愿者-买米" << endl;
}
};
// 抽象工厂类
class AbstractFactory {
public:
virtual Leifeng* CreateLeifeng() {
return new Leifeng;
}
};
// 下面是两个具体工厂类,分别与两个具体产品对应
// 学生雷锋工厂
class UndergraduateFactory : public AbstractFactory {
public:
Undergraduate* CreateLeifeng() {
return new Undergraduate;
}
};
// 志愿者雷锋工厂
class VolunteerFactory : public AbstractFactory {
public:
Volunteer* CreateLeifeng() {
return new Volunteer;
}
};
int main(int argc, char const *argv[]) {
// 想要生产Volunteer产品的话,只需要将此处的UndergraduateFactory更改为VolunteerFactory即可。
AbstractFactory* af = NULL;
af = new VolunteerFactory;
Leifeng* lf = NULL;
lf = af->CreateLeifeng();
lf->BuyRice();
lf->Sweep();
lf->Wash();
if (af != NULL) {
delete af;
af = NULL;
}
if (lf != NULL) {
delete lf;
lf = NULL;
}
return 0;
}
原型模式,用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。它主要面对的问题是:“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口。(1)原型模式实际上就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节;(2)一般在初始化的信息不发生变化的情况下,克隆是最好的办法,这既隐藏了对象创建的细节,有对性能是大大的提高,因为如果不用Clone,每次new,都需要执行一次构造函数,如果构造函数的执行时间很长,那么多次的执行这个初始化操作就实在是太低效了;(3)浅复制和深复制,浅复制是指被复制的对象的所有变量都含有与原来的对象相同的值,而所有对其他对象的引用都仍然指向原来的对象,而深复制是把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
原型模式本质上其实就是克隆,以个人简历为例进行举例说明:
// 深拷贝版本
#include
#include
#include
using namespace std;
template<class T>
class ICloneable {
public:
virtual T* clone() = 0;
};
// 工作经验类
class CWorkExperience {
public:
CWorkExperience() {}
CWorkExperience(const string& company, const string& workTime) {
m_strCompany = company;
m_strWorkTime = workTime;
}
CWorkExperience(const CWorkExperience& right) {
m_strCompany = right.m_strCompany;
m_strWorkTime = right.m_strWorkTime;
}
virtual ~CWorkExperience() {
cout << "CWorkExperience 析构" << endl;
printInfo();
}
void setCompany(const string& company) {
m_strCompany = company;
}
const string& getCompany() const {
return m_strCompany;
}
void setWorkTime(const string& workTime) {
m_strWorkTime = workTime;
}
const string& getWorkTime() const {
return m_strWorkTime;
}
void printInfo() {
cout << "Company: " << m_strCompany << endl;
cout << "WorkTime: " << m_strWorkTime << endl;
}
private:
string m_strWorkTime;
string m_strCompany;
};
// 简历类
class CResume : public ICloneable<CResume> {
public:
CResume() {}
~CResume() {
cout << "CResume 析构" << m_name << endl;
}
void setInfo(const string& name, const string& sex, int age) {
m_name = name;
m_sex = sex;
m_age = age;
}
void setExperience(const string& company, const string& workTime) {
m_experience.setCompany(company);
m_experience.setWorkTime(workTime);
}
CResume* clone() {
CResume* resume = new CResume;
resume->setInfo(m_name, m_sex, m_age);
resume->setExperience(m_experience.getCompany(), m_experience.getWorkTime());
return resume;
}
void printInfo() {
cout << "Name: " << m_name << endl;
cout << "Sex: " << m_sex << endl;
cout << "Age: " << m_age << endl;
cout << "Experience: " << endl;
m_experience.printInfo();
cout << endl;
}
protected:
string m_name;
string m_sex;
int m_age;
CWorkExperience m_experience; // 对象
};
int main(int argc, char const *argv[]) {
CResume re;
re.setInfo("Jacky", "Male", 20);
re.setExperience("MS", "2001.11 - 2005.11");
re.printInfo();
CResume* pClone = re.clone();
pClone->setInfo("Marry", "Female", 30);
pClone->setExperience("Google", "2006.01 - 2010.01");
pClone->printInfo();
delete pClone;
pClone = NULL;
return 0;
}
运行结果:
// 浅拷贝版本
#include
using namespace std;
#include
#include
#include
using namespace std;
// 克隆接口
template<class T>
class ICloneable {
public:
virtual T* clone() = 0;
};
// 工作经历类
class CWorkExperience {
public:
CWorkExperience() {}
CWorkExperience(const string& company, const string& workTime) {
m_strCompany = company;
m_strWorkTime = workTime;
}
CWorkExperience(const CWorkExperience& right) {
m_strCompany = right.m_strCompany;
m_strWorkTime = right.m_strWorkTime;
}
~CWorkExperience() {
cout << "CWorkExperience析构" << endl;
printInfo();
}
void setCompany(const string& company) {
m_strCompany = company;
}
const string& getCompany() const {
return m_strCompany;
}
void setWorkTime(const string& workTime) {
m_strWorkTime = workTime;
}
const string& getWorkTime() const {
return m_strWorkTime;
}
void printInfo() {
cout << "Company: " << m_strCompany << endl;
cout << "WorkTime: " << m_strWorkTime << endl;
}
private:
string m_strCompany; // company name
string m_strWorkTime; // work time
};
// 简历类
class CResume : public ICloneable<CResume> {
private:
// 只允许调用带参数的构造函数和拷贝构造函数
CResume() {m_experience = NULL;}
public:
// 带参构造函数
CResume(CWorkExperience* pWorkExperience) {
// 不负责内存分配 只是共享
m_experience = pWorkExperience;
}
// 带参拷贝构造函数
CResume(const CResume& right) {
m_name = right.m_name;
m_sex = right.m_sex;
m_age = right.m_age;
// 注意这里是指针赋值 属于浅拷贝
m_experience = right.m_experience;
}
~CResume() {
cout << "CResume析构 " << m_name << endl;
}
void setInfo(const string& name, const string& sex, int age) {
m_name = name;
m_sex = sex;
m_age = age;
}
void setExperience(const string& company, const string& workTime) {
m_experience->setCompany(company);
m_experience->setWorkTime(workTime);
}
CResume* clone() {
// 调用拷贝构造函数 浅拷贝
CResume* resume = new CResume(*this);
return resume;
}
void printInfo() {
cout << "Name: " << m_name << endl;
cout << "Sex: " << m_sex << endl;
cout << "Age: " << m_age << endl;
cout << "Experience: " << endl;
m_experience->printInfo();
cout << endl;
}
protected:
string m_name;
string m_sex;
int m_age;
CWorkExperience* m_experience;// 指针 聚合
};
int main(int argc, char const *argv[]) {
CWorkExperience* pWorkExperience = new CWorkExperience("MS", "2001.11 - 2005.11");
CResume re(pWorkExperience); // 只能这样构造 无参构造被屏蔽掉了
re.setInfo("Jacky", "Male", 20);
re.printInfo();
CResume* pClone = re.clone(); // 指针赋值 浅拷贝
//delete pWorkExperience; // 这里如果调用delete 程序会崩溃(因为是共享)
pClone->setInfo("Marry", "Female", 30);
pClone->setExperience("Google", "2006.01 - 2010.01");
pClone->printInfo();
re.printInfo(); // 发现原对象的workExperience属性已经被修改
delete pClone;
delete pWorkExperience;
pClone = NULL;
pWorkExperience = NULL;
return 0;
}
模板方法模式,就是定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
AbstractClass是抽象类,其实也就是一个抽象模板,定义并实现了一个模板方法,这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的框架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现,顶级逻辑也有可能调用一些具体方法;ConcreteClass实现父类所定义的一个或多个抽象方法,每一个AbstractClass都可以有任意多个ConcreteClass与之对应,而每一个ConcreteClass都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。看一个例子,为了避免学生抄错试题,所以让老师出一份试卷,学生只要在试卷上写出自己的答案就行:
#include
#include
// AbstractClass,实现了一个模板,定义了算法的骨架,组成骨架的具体步骤放在子类中实现
class TestPaper {
public:
void TestQuestion1() {
std::cout << "杨过得到,后来给了郭靖,练成倚天剑、屠龙刀的玄铁可能是【】a.球磨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维" << std::endl;
std::cout << "答案:" << Answer1() << std::endl;
}
void TestQuestion2() {
std::cout << "杨过、程英、陆无双铲除了情花,造成【】a.使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化" << std::endl;
std::cout << "答案:" << Answer2() << std::endl;
}
void TestQuestion3() {
std::cout << "蓝凤凰致使华山师徒、桃谷六仙呕吐不止,如果你是大夫,会给他们开什么药【】a.阿司匹林 b.牛黄解毒片 c.氟哌酸 d.让他们喝大量牛奶" << std::endl;
std::cout << "答案:" << Answer3() << std::endl;
}
protected:
virtual std::string Answer1() {
return "";
}
virtual std::string Answer2() {
return "";
}
virtual std::string Answer3() {
return "";
}
};
//ConcreteClass,实现具体步骤(学生A抄的试卷)
class TestPaperA : public TestPaper {
protected:
virtual std::string Answer1() {
return "b";
}
virtual std::string Answer2() {
return "c";
}
virtual std::string Answer3() {
return "a";
}
};
//ConcreteClass,实现具体步骤(学生B抄的试卷)
class TestPaperB : public TestPaper {
protected:
virtual std::string Answer1() {
return "c";
}
virtual std::string Answer2() {
return "a";
}
virtual std::string Answer3() {
return "a";
}
};
int main(int argc, char const *argv[]) {
std::cout << "学生甲抄的试卷:" << std::endl;
TestPaper* studentA = new TestPaperA();
studentA->TestQuestion1();
studentA->TestQuestion2();
studentA->TestQuestion3();
std::cout << std::endl;
std::cout << "学生乙抄的试卷:" << std::endl;
TestPaper* studentB=new TestPaperB();
studentB->TestQuestion1();
studentB->TestQuestion2();
studentB->TestQuestion3();
std::cout << std::endl;
delete studentA;
delete studentB;
return 0;
}
运行结果:
总结:当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。通过模板方法模式,把这些行为搬移到单一的地方,这样帮助子类摆脱重复的不变行为的纠缠。注意,上述例子中,AbstractClass为TestPaper类,ConcreteClass为TestPaperA和TestPaperB,而上述的UML图中的TemplateMethod()
为TestQuestion1()
,primitiveOperation1为函数Answer1()
,primitiveOperation1为函数Answer2()
等等。
外观模式,为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
外观模式在什么时候使用呢?分为三个阶段:首先,在设计初期阶段,应该要有意识的将不同的两个层分离;第二,在开发阶段,子系统往往因为不断的重构演化而变得越来越复杂,大多数的模式使用时也会产生很多很小的类,这本是好事儿,但是也给外部调用他们的用户程序带来了使用上的困难,增加外观Facade可以提供一个简单的接口,减少他们之间的依赖;第三,在维护一个遗留的大型系统时,可能这个系统已经非常难以维护和扩展了,但因为它包含非常重要的功能,新的需求开发必须要依赖于它,此时用外观模式Facade也是非常合适的。具体而言,为新系统开发一个外观Facade类,来提供设计粗糙或高度复杂的遗留代码的比较清晰简单的接口,让新系统与Facade对象交互,Facade与遗留代码交互所有复杂的工作。使用外观模式的好处如下图所示:
看一个例子,股民只把钱交给基金,然后由基金经理人与上千支股票和投资产品打交道(基金经理人比股民更加专业,这样股民不用关心股票的具体操作者,也比较容易达到好的投资效果):
#include
#include
// SubSystem Class,实现子系统的功能,处理Facade对象指派的任务。注意子类中没有Facade任何信息,即没有对Facade对象的引用。
// 下面是四个子系统的类(相当于四支股票)
class SubSystemOne {
public:
void MethodOne() {
std::cout<<"子系统方法一"<<std::endl;
}
};
class SubSystemTwo {
public:
void MethodTwo() {
std::cout<<"子系统方法二"<<std::endl;
}
};
class SubSystemThree {
public:
void MethodThree() {
std::cout<<"子系统方法三"<<std::endl;
}
};
class SubSystemFour {
public:
void MethodFour() {
std::cout<<"子系统方法四"<<std::endl;
}
};
// Facade Class,外观类,知道有哪些子系统类,负责处理请求,将客户的请求代理给适当的子系统对象。
// 相当于基金经理人
class Facade {
private:
SubSystemOne* one;
SubSystemTwo* two;
SubSystemThree* three;
SubSystemFour* four;
public:
Facade() {
one=new SubSystemOne();
two=new SubSystemTwo();
three=new SubSystemThree();
four=new SubSystemFour();
}
~Facade() {
delete one;
delete two;
delete three;
delete four;
}
void MethodA() {
std::cout<<"方法组A()------"<<std::endl;
one->MethodOne();
two->MethodTwo();
four->MethodFour();
std::cout<<std::endl;
}
void MethodB() {
std::cout<<"方法组B()------"<<std::endl;
two->MethodTwo();
three->MethodThree();
std::cout<<std::endl;
}
};
int main(int argc, char const *argv[]) {
Facade* facade=new Facade();
facade->MethodA();
facade->MethodB();
delete facade;
return 0;
}
建造者模式(Builder),将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式要求建造过程必须是稳定的。
Builder是为创建一个Product对象的各个部件指定的抽象接口;ConcreteBuilder是具体创建者,实现Builder接口,构造和装配各个部件;Product是具体的产品角色;Director是指挥者,它是构建一个使用Builder接口的对象。什么时候使用建造者模式?它主要是用于创建一些复杂的对象,这些对象内部构造间的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化。使用建造者模式的好处是,建造者模式的好处就是使得建造代码与表示代码分离,由于建造者隐藏了 该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了。看一个例子,设计一个画小人的程序,画一个胖小孩和一个瘦小孩:
#include
#include
#include
//Product Class,产品类,有多个部件组成。
class Product {
private:
std::vector<std::string> parts;
public:
// 添加产品部件
void Add(std::string part) {
parts.push_back(part);
}
//列举所有的产品部件
void Show() {
std::cout << "产品 创建------" << std::endl;
std::vector<std::string>::iterator it;
for(it = parts.begin(); it != parts.end(); it++) {
std::cout << *it << std::endl;
}
}
};
// Builder,抽象建造者
class Builder {
public:
virtual void BuildPartA() = 0;
virtual void BuildPartB() = 0;
virtual Product* GetResult() = 0;
};
// ConcreteBuilder1,具体建造者类(画一个瘦小孩)
class ConcreteBuilder1 : public Builder {
private:
Product* product;
public:
ConcreteBuilder1() {
product = new Product();
}
~ConcreteBuilder1() {
delete product;
}
void BuildPartA() {
product->Add("部件A");
}
void BuildPartB() {
product->Add("部件B");
}
Product* GetResult() {
return product;
}
};
//ConcreteBuilder2,具体建造者类(画一个胖小孩)
class ConcreteBuilder2 : public Builder {
private:
Product* product;
public:
ConcreteBuilder2() {
product = new Product();
}
~ConcreteBuilder2() {
delete product;
}
void BuildPartA() {
product->Add("部件X");
}
void BuildPartB() {
product->Add("部件Y");
}
Product* GetResult() {
return product;
}
};
//Director Class,指挥者类。
class Director {
public:
void Construct(Builder* builder) {
builder->BuildPartA();
builder->BuildPartB();
}
};
//Client,客户不知道具体的建造过程。
int main(int argc, char const *argv[]) {
Director* director = new Director();
Builder* builder1 = new ConcreteBuilder1();
Builder* builder2 = new ConcreteBuilder2();
std::cout << "指挥者用ConcreteBuilder1的方法建造产品:" << std::endl;
director->Construct(builder1);
Product* p1 = builder1->GetResult();
p1->Show();
std::cout << std::endl;
std::cout << "指挥者用ConcreteBuilder2的方法建造产品:" << std::endl;
director->Construct(builder2);
Product* p2 = builder2->GetResult();
p2->Show();
std::cout << std::endl;
delete director;
delete builder1;
delete builder2;
return 0;
}
观察者模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
Subject类可以翻译为主题或者抽象通知者,一般用一个抽象类或者一个接口实现,它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象;Observer类,抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,这个接口叫做更新接口,抽象观察者一般用一个抽象类或者一个接口实现,更新接口通常包含一个Update()
方法,这个方法叫做更新方法;ConcreteSubject类叫做具体主题或者具体通知者,将有关状态存入具体观察者对象,在具体主题的内部状态改变时,给所有登记过的观察者发出通知;ConcreteObserver类,具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调,具体观察者角色可以保存一个指向具体主题对象的引用。Subject维护一个Observer列表,Subject执行Notify()
时就执行列表中的每个Observer的Update()
。什么时候用观察者模式?(1)当一个对象的改变需要同时改变其他对象的时候;(2)而且不知道具体有多少对象有待改变时,应该考虑使用观察者模式;(3)当一个抽象模型有两个方面,其中一方面依赖于另一方面,这时用观察者模式可以将这两者封装在独立的对象中使他们各自独立地改变和复用。观察者模式所做的工作其实就是在解除耦合,让耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不会影响另一边的变化。设计一个观察者,通知老板回来了:
#include
#include
#include
#include
class Subject;
//Observer,抽象观察者
class Observer {
protected:
std::string name;
Subject* sub;
public:
Observer() {}
Observer(std::string name, Subject* sub) {
this->name = name;
this->sub = sub;
}
virtual void Update() {
std::cout << "Observer.Update()" << std::endl;
}
bool operator==(const Observer& observer)const {
return (this->name == observer.name)&&(this->sub == observer.sub);
}
};
//Subject,抽象通知者或者主题
class Subject {
protected:
std::string SubjectState;
public:
virtual void Attach(Observer* observer) = 0;
virtual void Detach(Observer* observer) = 0;
virtual void Notify() = 0;
std::string GetSubjectState() {
return SubjectState;
}
void SetSubjectState(std::string state) {
this->SubjectState = state;
}
};
//ConcreteSubject,具体通知者或者具体主题。
//老板也可以是通知者
class Boss : public Subject {
private:
std::list<Observer*> observers;
std::string action;
public:
void Attach(Observer* observer) {
observers.push_back(observer); // 把想通知的人加进来
}
void Detach(Observer* observer) {
std::list<Observer*>::iterator it;
for(it = observers.begin(); it != observers.end(); it++) {
if (*it == observer) {
observers.erase(it); // 把不想通知的人删掉
break;
}
}
}
void Notify() {
std::list<Observer*>::iterator it;
for (it = observers.begin(); it != observers.end(); it++) {
(**it).Update();
}
}
};
//ConcreteObserver,具体观察者,股票观察者
class StockObserver : public Observer {
public:
StockObserver() {}
StockObserver(std::string name, Subject* sub) {
this->name = name;
this->sub = sub;
}
void Update() {
std::cout << sub->GetSubjectState() << " " << name << " " << "关闭股市行情,继续工作!" << std::endl;
}
};
//ConcreteObserver,具体观察者,NBA观察者
class NBAObserver : public Observer {
public:
NBAObserver() {}
NBAObserver(std::string name, Subject* sub) {
this->name = name;
this->sub = sub;
}
void Update() {
std::cout << sub->GetSubjectState() << " " << name << " " << "关闭NBA直播,继续工作!" << std::endl;
}
};
int main(int argc, char const *argv[]) {
//通知者
Subject* huhansan = new Boss();
//4个观察者实例
Observer* tongshi1 = new StockObserver("魏关姹", huhansan);
Observer* tongshi2 = new StockObserver("易管察", huhansan);
Observer* tongshi3 = new NBAObserver("霍华德", huhansan);
Observer* tongshi4 = new NBAObserver("林书豪", huhansan);
//将4个观察者都加入到通知者的通知队列中
huhansan->Attach(tongshi1);
huhansan->Attach(tongshi2);
huhansan->Attach(tongshi3);
huhansan->Attach(tongshi4);
//魏关姹没有被老板通知到,减去。
huhansan->Detach(tongshi1);
huhansan->SetSubjectState("我胡汉三回来了!");
//通知
huhansan->Notify();
delete huhansan;
delete tongshi1;
delete tongshi2;
delete tongshi3;
delete tongshi4;
std::cout << "" << std::endl;
return 0;
}
设计一个程序,可以在SQL Serverl或者Access操作表User和表Department:
#include
#include
using namespace std;
// 数据库表项:User
class User {
private:
int id;
string name;
public:
int getID() {
return id;
}
string getName() {
return name;
}
void setID(int ID) {
this->id = ID;
}
void setName(string NAME) {
this->name = NAME;
}
};
// 数据库表项:Department
class Department {
private:
int id;
string name;
public:
int getID() {
return id;
}
string getName() {
return name;
}
void setID(int ID) {
this->id = ID;
}
void setName(string NAME) {
this->name = NAME;
}
};
// 抽象产品A:IUser
class IUser {
public:
virtual void Insert(User user) = 0;
virtual User* GetUser(int id) = 0;
};
// 具体产品A1:SqlserverUser
class SqlserverUser : public IUser {
public:
void Insert(User user) {
cout << "在SQL Server中给User表增加了一条记录" << endl;
}
User* GetUser(int id) {
cout << "在SQL Server中根据ID得到User表一条记录" << endl;
return NULL;
}
};
// 具体产品A2:AccessUser
class AccessUser : public IUser {
public:
void Insert(User user) {
cout << "在Access中给User表增加了一条记录" << endl;
}
User* GetUser(int id) {
cout << "在Access中根据ID得到User表一条记录" << endl;
return NULL;
}
};
// 抽象产品B:IDepartment
class IDepartment {
public:
virtual void Insert(Department department) = 0;
virtual Department* GetDepartment(int id) = 0;
};
// 具体产品B1:SqlserverDepartment
class SqlserverDepartment : public IDepartment {
public:
void Insert(Department department) {
cout << "在SQL Server中给Department表添加了一条记录" << endl;
}
Department* GetDepartment(int id) {
cout << "在SQL Server中根据ID得到Department表的一条记录" << endl;
return NULL;
}
};
// 具体产品B2:AccessDepartment
class AccessDepartment : public IDepartment {
public:
void Insert(Department department) {
cout << "在Access中给Department表添加了一条记录" << endl;
}
Department* GetDepartment(int id) {
cout << "在Access中根据ID得到Department表的一条记录" << endl;
return NULL;
}
};
// 抽象工厂:IFactory
class IFactory {
public:
virtual IUser* CreateUser() = 0;
virtual IDepartment* CreateDepartment() = 0;
};
// 具体工厂1:SqlServerFactory
class SqlserverFactory : public IFactory {
public:
IUser* CreateUser() {
return new SqlserverUser;
}
IDepartment* CreateDepartment() {
return new SqlserverDepartment;
}
};
// 具体工厂2:AccessFactory
class AccessFactory : public IFactory {
public:
IUser* CreateUser() {
return new AccessUser;
}
IDepartment* CreateDepartment() {
return new AccessDepartment;
}
};
// 客户端
int main(int argc, char const *argv[]) {
User user;
Department department;
// ConcreteFactory1
IFactory* factory = NULL;
factory = new SqlserverFactory;
// ProductA1
IUser* iu = NULL;
iu = factory->CreateUser();
iu->Insert(user);
iu->GetUser(1);
// ProductB1
IDepartment* id = NULL;
id = factory->CreateDepartment();
id->Insert(department);
id->GetDepartment(1);
if (factory != NULL) {
delete factory;
factory = NULL;
}
if (iu != NULL) {
delete iu;
iu = NULL;
}
if (id != NULL) {
delete id;
id = NULL;
}
return 0;
}
运行结果:
抽象工厂模式(Abstract Factory),提供一个创建一系列相关或互相依赖对象的接口,而无需指定他们具体的类。包括抽象工厂、具体工厂(包括具体工厂1和具体工厂2,具体工厂1用于生产具体产品A1和具体产品B1,具体工厂2用于生产具体产品A2和具体产品B2)、抽象产品(包括抽象产品A和抽象产品B)、具体产品(包括抽象产品A所对应的具体产品A1和A2,以及抽象产品B所对应的具体产品B1和B2)。上述的1和2分别代表上述例子中的Sqlserver数据库和Access数据库,上述的A和B分别代表数据库中的User表和Department表。
抽象工厂模式是对工厂方法模式的改进,用于处理产品不只有一类的情况(工厂方法模式下,产品只有User这一类,而抽象工厂模式下,产品包括User和Department两类)。在以下情况下应当考虑使用抽象工厂模式:一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的;这个系统有多于一个的产品族,而系统只消费其中某一产品族;同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来;系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。在上例中,产品族包括两个,即1和2,也就是Sqlserver数据库和Access数据库,每个产品族里面又包含两类产品,即A和B,也就是User表和Department表,而每个产品族中的产品要一起使用,就是说产品族1中的两类产品A和B要一起使用,也就是说在SqlServer数据库中SqlServerUser表和SqlServerDepartment表要一起使用,Access数据库同理。
状态模式(State),当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。(1)状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类,看起来,状态模式好像是神通广大很厉害似的——居然能够“修改自身的类”;(2)适用场景:状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况,把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简单化(简单来说,就是把各种if else
转变成了一个个的具体状态,原来if else
每种情况下的操作现在转换到了某个具体状态中);当一个对象行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式了。
Context类在该类内部维护一个ConcreteState子类的一个实例,这个实例定义当前的状态;State类是抽象状态类,定义一个 接口以封装与Context的一个特定状态相关的行为;ConcreteStateA和ConcreteStateB类是具体状态类,每一个子 类实现一个与Context的一个状态相关的行为。设计一个表示一天之中不同时间的不同状态的程序:
#include
#include
using namespace std;
class Work;
class State {
public:
State() {}
virtual void writeProgram(Work* w) {}
};
class ForenoonState : public State {
public:
void writeProgram(Work* w) {
if (w->getHour() < 12) {
cout << "当前时间:" << w->getHour() << "点 " << "上午工作,精神百倍" << endl;
} else {
w->setState(new NoonState);
w->writeProgram();
}
}
};
class NoonState : public State {
public:
void writeProgram(Work* w) {
if (w->getHour() < 13) {
cout << "当前时间:" << w->getHour() << "点 " << "饿了,午饭;犯困,午休" << endl;
} else {
w->setState(new AfternoonState);
w->writeProgram();
}
}
};
class AfternoonState : public State {
public:
void writeProgram(Work* w) {
if (w->getHour() < 17) {
cout << "当前时间:" << w->getHour() << "点 " << "下午状态还不错,继续努力" << endl;
} else {
w->setState(new EveningState);
w->writeProgram();
}
}
};
class EveningState : public State {
public:
void writeProgram(Work* w) {
if (w->getFinish()) {
w->setState(new RestState);
w->writeProgram();
} else {
if (w->getHour() < 21) {
cout << "当前时间:" << w->getHour() << "点 " << "加班哦,疲惫至极" << endl;
} else {
w->setState(new SleepingState);
w->writeProgram();
}
}
}
};
class SleepingState : public State {
public:
void writeProgram(Work* w) {
cout << "当前时间:" << w->getHour() << "点 " << "不行了,睡着了" << endl;
}
};
class RestState : public State {
public:
void writeProgram(Work* w) {
cout << "当前时间:" << w->getHour() << "点 " << "下班回家了" << endl;
}
};
// 这里的Work就是状态模式中的Context
class Work {
private:
State* current;
double Hour;
bool finish;
public:
Work() {
current = new ForenoonState;
Hour = 9;
finish = false;
}
~Work() {
if (current != 0)
delete current;
}
double getHour() {
return Hour;
}
void setHour(double HOUR) {
Hour = HOUR;
}
bool getFinish() {
return finish;
}
void setFinish(bool FINISH) {
finish = FINISH;
}
void setState(State* s) {
if (current != 0)
delete current;
current = s;
}
void writeProgram() {
current->writeProgram(this);
}
};
int main(int argc, char const *argv[]) {
Work emergencyProjects;
emergencyProjects.setHour(9);
emergencyProjects.writeProgram();
emergencyProjects.setHour(10);
emergencyProjects.writeProgram();
emergencyProjects.setHour(12);
emergencyProjects.writeProgram();
emergencyProjects.setHour(13);
emergencyProjects.writeProgram();
emergencyProjects.setHour(14);
emergencyProjects.writeProgram();
emergencyProjects.setHour(17);
emergencyProjects.writeProgram();
emergencyProjects.setFinish(false);
emergencyProjects.setHour(19);
emergencyProjects.writeProgram();
emergencyProjects.setHour(22);
emergencyProjects.writeProgram();
return 0;
}
适配器模式,将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原来由于接口不兼容而不能一起工作的那些类可以一起工作。想使用一个已存在的类,但是如果它的接口,也就是它的方法和你的要求不相同时,就应该考虑用适配器模式;用了适配器模式,客户代码统一调用统一接口就行了,这样可以更简单,更直接,更紧凑;要在双方都不太容易修改的时候再使用适配器模式适配,而不是一有不同就使用它。
Client需要Request()
函数,Adaptee提供的是SpecificRequest()
函数,Adapter提供一个Request()
函数将Adaptee和SpecificeRequest()
函数封装起来。Target是客户所期待的接口,Target可以是具体的或抽象的类,也可以是接口;Adaptee是需要适配的类;Adapter通过在内部包装一个Adaptee对象,把源接口转换成目标接口。来看一个例子,姚明是外援,需要通过请翻译才能听懂教练的话:
#include
#include
#include
// Target,此处为运动员
class Player {
protected:
std::string name;
public:
Player(std::string name) {
this->name = name;
}
virtual void Attack() = 0;
virtual void Defense() = 0;
};
// Adaptee,此处为外籍中锋,它的接口和Target的接口不一样,需要翻译来帮忙转换
class ForeignCenter {
private:
std::string name;
public:
void SetName(std::string name) {
this->name = name;
}
std::string GetName() {
return name;
}
void ForeignAttack() {
std::cout << "外籍中锋 " << name << " 进攻" << std::endl;
}
void ForeignDefense() {
std::cout << "外籍中锋 " << name<<" 防守" << std::endl;
}
};
// Adapter,此处为翻译
class Translator : public Player {
private:
ForeignCenter* wjzf;
public:
Translator(std::string name) : Player(name) {
wjzf = new ForeignCenter;
wjzf->SetName(name);
}
~Translator() {
delete wjzf;
}
void Attack() {
wjzf->ForeignAttack();
}
void Defense() {
wjzf->ForeignDefense();
}
};
// 下面是普通的 接口和Target接口一样的 3个子类,必须要翻译
// 前锋
class Forwards : public Player {
public:
Forwards(std::string name) : Player(name) {}
void Attack() {
std::cout << "前锋 " << name << " 进攻" << std::endl;
}
void Defense() {
std::cout << "前锋 " << name << " 防守" << std::endl;
}
};
// 中锋
class Center : public Player {
public:
Center(std::string name) : Player(name) {}
void Attack() {
std::cout << "中锋 " << name << " 进攻" << std::endl;
}
void Defense() {
std::cout << "中锋 " << name << " 防守" << std::endl;
}
};
// 后卫
class Guards : public Player {
public:
Guards(std::string name) : Player(name) {}
void Attack() {
std::cout << "后卫 " << name<<" 进攻" << std::endl;
}
void Defense() {
std::cout << "后卫 " << name<<" 防守" << std::endl;
}
};
int main(int argc, char const *argv[]) {
Player* b = new Forwards("巴蒂尔");
b->Attack();
Player* m = new Guards("麦克格雷迪");
m->Attack();
// 翻译告诉姚明,教练让你既要进攻,又要防守
Player* ym = new Translator("姚明");
ym->Attack();
ym->Defense();
delete b;
delete m;
delete ym;
return 0;
}
备忘录(Memento),在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将对象恢复到原先保存的状态。Memento模式比较适用于功能比较复杂的,但需要维护或记录属性历史的类,或者需要保存的属性只是众多属性中的一小部分时,Originator可以根据保存的Memento信息还原到迁移状态。与命令模式的关系是:如果在某个系统中使用命令模式时,需要实现命令的撤销功能,那么命令模式可以使用备忘录模式来存储可撤销操作的状态。
备份内容到Memento,用的时候再从Memento中取出来,Caretaker负责管理这些操作。Originator(发起人)负责创建一个Memento,用以记录当前时刻它的内部状态,并可以使用备忘录恢复内部状态,Originator可以根据需要决定Memento存储Originator的哪些内部状态;Memento(备忘录)负责存储Originator对象的内部状态,并可以防止Originator以外的其他对象访问备忘录Memento,备忘录有两个接口,Caretaker只能看到备忘录的窄接口,它只能将备忘录传递给其他对象,Originator能够看到一个宽接口,允许它访问先前状态所需的所有数据;Caretaker(管理者)负责保存包备忘录Memento,不能对备忘录的内容进行操作或检查。写一个例子,保存游戏角色当前的血量、战斗力等数值,等到需要的时候可以返回保存的数值:
#include
#include
// Memento类,备忘录,此处为角色状态存储箱RoleStateMemento class
class RoleStateMemento {
private:
// 生命力
int vit;
// 攻击力
int atk;
// 防御力
int def;
public:
RoleStateMemento(int vit, int atk, int def) {
this->vit = vit;
this->atk = atk;
this->def = def;
}
int GetVitality() {
return vit;
}
void SetVitality(int vit) {
this->vit = vit;
}
int GetAttack() {
return atk;
}
void SetAttack(int atk) {
this->atk = atk;
}
int GetDefense() {
return def;
}
void SetDefense(int def) {
this->def = def;
}
};
// Originator,发起人,此处为游戏角色,GameRole class
class GameRole {
private:
// 生命力
int vit;
// 攻击力
int atk;
// 防御力
int def;
public:
int GetVitality() {
return vit;
}
void SetVitality(int vit) {
this->vit = vit;
}
int GetAttack() {
return atk;
}
void SetAttack(int atk) {
this->atk = atk;
}
int GetDefense() {
return def;
}
void SetDefense(int def) {
this->def = def;
}
void GetInitState() {
this->vit = 100;
this->atk = 100;
this->def = 100;
}
void Fight() {
this->vit = 0;
this->atk = 0;
this->def = 0;
}
void StateDisplay() {
std::cout << "当前角色状态:" << std::endl;
std::cout << "体力:" << this->vit << std::endl;
std::cout << "生命力:" << this->atk << std::endl;
std::cout << "防御力:" << this->def << std::endl << std::endl;
}
// “保存角色状态”方法,将游戏角色的三个状态值通过实例化“角色状态存储箱”返回
RoleStateMemento* SaveState() {
return new RoleStateMemento(vit, atk, def);
}
// “恢复角色状态”方法,可将外部的“角色状态存储箱”中的状态值恢复给游戏角色
void RocoveryState(RoleStateMemento memento) {
this->vit = memento.GetVitality();
this->atk = memento.GetAttack();
this->def = memento.GetDefense();
}
};
// Caretaker,管理者,此处为游戏角色管理类,RoleStateCaretaker class
class RoleStateCaretaker {
private:
RoleStateMemento* memento;
public:
RoleStateCaretaker() {
memento = NULL;
}
~RoleStateCaretaker() {
if (memento != NULL) {
delete memento;
memento = NULL;
}
}
RoleStateMemento* GetMemento() {
return memento;
}
void SetMemento(RoleStateMemento* memento) {
this->memento = memento;
}
};
int main(int argc, char const *argv[]) {
// 大战Boss前
GameRole* lixiaoyao = new GameRole();
lixiaoyao->GetInitState();
lixiaoyao->StateDisplay();
// 保存进度
RoleStateCaretaker* stateAdmin = new RoleStateCaretaker();
stateAdmin->SetMemento(lixiaoyao->SaveState());
// 大战Boss时,损耗严重
lixiaoyao->Fight();
lixiaoyao->StateDisplay();
// 恢复之前状态
lixiaoyao->RocoveryState(*stateAdmin->GetMemento());
lixiaoyao->StateDisplay();
delete lixiaoyao;
delete stateAdmin;
return 0;
}
组合模式(Composite),将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。当发现需求中是体现部分与整体层次的结构时,以及希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑用组合模式了。使用组合模式的好处是:(1)组合模式定义了包含基本对象(Leaf)和组合对象(Composite)的类层次结构,基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断地地柜下去,客户代码中,任何用到基本对象的地方都可以使用组合对象了;(2)用户不用关心到底是处理一个叶子节点还是处理一个组合组件,也就不用为定义组合而写一些判断语句了;(3)简而言之,组合模式让客户可以一致的使用组合结构和单个对象。
Leaf是叶子,Composite是非叶子节点,Composite包含Leaf。Component为组合中的对象声明接口,在适当情况下,实现所有类共有接口的默认行为,声明一个接口用于访问和管理Component 的子部件;Leaf在组合中是叶节点对象,叶节点没有子节点;Composite定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关的操作,比如增加Add和删除Remove。看一个总公司与分公司的例子:
#include
#include
#include
#include
// Component:此处为抽象公司类
class Company {
protected:
std::string name;
public:
Company(std::string name) {
this->name = name;
}
// 增加节点
virtual void Add(Company* c) = 0;
// 删除节点
virtual void Remove(Company* c) = 0;
// 展示
virtual void Display(int depth) = 0;
// 职责
virtual void LineOfDuty() = 0;
// 运算符重载
inline bool operator==(const Company &company) const {
return (this->name == company.name);
}
};
// Composite:具体公司类
class ConcreteCompany : public Company {
private:
std::list<Company*> *children;
public:
ConcreteCompany(std::string name) : Company(name) {
children = new std::list<Company*>;
}
~ConcreteCompany() {
for (std::list<Company*>::iterator it = children->begin(); it != children->end(); it++)
delete *it;
delete children;
}
// 增加叶子节点
void Add(Company* c) {
children->push_back(c);
}
// 删除叶子节点
void Remove(Company* c) {
for (std::list<Company*>::iterator it = children->begin(); it != children->end(); it++) {
if (**it == *c) {
children->erase(it);
break;
}
}
}
// 打印
void Display(int depth) {
for (int i = 0; i < depth; i++)
std::cout << "-";
std::cout << name << std::endl;
for (std::list<Company*>::iterator it = children->begin(); it != children->end(); it++)
(*it)->Display(depth + 4);
}
// 职责
void LineOfDuty() {
for (std::list<Company*>::iterator it = children->begin(); it != children->end(); it++)
(*it)->LineOfDuty();
}
};
// Leaf:人力资源部
class HRDepartment : public Company {
public:
HRDepartment(std::string name) : Company(name) {}
void Add(Company* c) {}
void Remove(Company* c) {}
void Display(int depth) {
for (int i = 0; i < depth; i++)
std::cout << "-";
std::cout << name << std::endl;
}
void LineOfDuty() {
std::cout << name << " 员工招聘培训管理" << std::endl;
}
};
// Leaf:财务部
class FinanceDepartment : public Company {
public:
FinanceDepartment(std::string name) : Company(name) {}
void Add(Company* c) {}
void Remove(Company* c) {}
void Display(int depth) {
for (int i = 0; i < depth; i++)
std::cout << "-";
std::cout << name << std::endl;
}
void LineOfDuty() {
std::cout << name << " 公司财务收支管理" << std::endl;
}
};
int main(int argc, char const *argv[]) {
Company* root = new ConcreteCompany("北京总公司");
root->Add(new HRDepartment("总公司人力资源部"));
root->Add(new FinanceDepartment("总公司财务处"));
Company* comp = new ConcreteCompany("上海华东分公司");
comp->Add(new HRDepartment("华东分公司人力资源部"));
comp->Add(new FinanceDepartment("华东分公司财务处"));
root->Add(comp);
Company* comp1 = new ConcreteCompany("南京办事处");
comp1->Add(new HRDepartment("南京办事处人力资源部"));
comp1->Add(new FinanceDepartment("南京办事处财务处"));
comp->Add(comp1);
Company* comp2 = new ConcreteCompany("杭州办事处");
comp2->Add(new HRDepartment("杭州办事处人力资源部"));
comp2->Add(new FinanceDepartment("杭州办事处财务处"));
comp->Add(comp2);
std::cout << "结构图:" << std::endl<<std::endl;
root->Display(1);
std::cout << std::endl << "职责:" << std::endl << std::endl;
root->LineOfDuty();
delete root;
return 0;
}
迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。当需要访问一个聚集对象,而且不管这些对象时什么都需要遍历的时候,应该考虑用迭代器模式;需要对聚集有多种遍历时,可以考虑用迭代器模式;为遍历不同的聚集结构提供如开始、下一个、是否结束、当前哪一项等统一的接口,考虑用迭代器模式。迭代器模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以不暴露集合的内部结构,又可让外部代码透明地访问集合内部的数据。
看一个公车售票员售票的例子:
#include
#include
#include
#include
typedef std::string object;
class ConcreteAggregate;
class Aggregate;
// 迭代器抽象类
class Iterator {
public:
virtual object First() = 0;
virtual object Next() = 0;
virtual bool IsDone() = 0;
virtual object CurrentItem() = 0;
};
// 具体迭代器类,从前往后的迭代器
class ConcreteIterator : public Iterator {
private:
ConcreteAggregate* aggregate;
int current;
public:
ConcreteIterator(Aggregate* aggregate) {
this->aggregate = (ConcreteAggregate*)aggregate;
current = 0;
}
object First() {
return aggregate->GetVector()->at(0);
}
object Next() {
current++;
if (current < aggregate->GetVector()->size())
return aggregate->GetVector()->at(current);
}
bool IsDone() {
return (current >= aggregate->GetVector()->size() ? true : false);
}
object CurrentItem() {
return aggregate->GetVector()->at(current);
}
};
// 具体迭代器类,从后往前的迭代器
class ConcreteIteratorDesc : public Iterator {
private:
ConcreteAggregate* aggregate;
int current;
public:
ConcreteIteratorDesc(Aggregate* aggregate) {
this->aggregate = (ConcreteAggregate*)aggregate;
current = (((ConcreteAggregate*)aggregate)->GetVector()->size()) - 1;
}
object First() {
return *(aggregate->GetVector()->end());
}
object Next() {
current--;
if (current >= 0)
return aggregate->GetVector()->at(current);
}
bool IsDone() {
return (current < 0 ? true : false);
}
object CurrentItem() {
return aggregate->GetVector()->at(current);
}
};
// 聚集抽象类
class Aggregate {
public:
virtual Iterator* CreateIterator() = 0;
virtual std::vector<object>* GetVector() = 0;
};
// 具体聚集类
class ConcreteAggregate : public Aggregate {
private:
std::vector<object> *items;
public:
ConcreteAggregate() {
items = new std::vector<object>;
}
~ConcreteAggregate() {
delete items;
}
// 产生从前往后的迭代器
Iterator* CreateIterator() {
Iterator* it = new ConcreteIterator(this);
return it;
}
// 产生从后往前的迭代器
Iterator* CreateIteratorDesc() {
Iterator* it = new ConcreteIteratorDesc(this);
return it;
}
std::vector<object>* GetVector() {
return items;
}
int Count() {
return items->size();
}
object GetElement(int index) {
return items->at(index);
}
void SetElement(int index, object o) {
items->at(index) = o;
}
};
int main(int argc, char const *argv[]) {
// 公交车,即聚集对象
ConcreteAggregate* a = new ConcreteAggregate();
// 新上来的乘客
a->GetVector()->push_back("大鸟");
a->GetVector()->push_back("小菜");
a->GetVector()->push_back("行李");
a->GetVector()->push_back("老外");
a->GetVector()->push_back("公交内部人员");
a->GetVector()->push_back("小偷");
// 售票员出场,先看好了上车的是哪些人,即声明了迭代器对象。
// 下面两种获取迭代器的方法都可以
// Iterator* i=new ConcreteIterator(a);
// 产生从前往后的迭代器
Iterator* it1 = a->CreateIterator();
// 告知每一位乘客买票
std::cout << "从前往后的迭代器:" << std::endl << std::endl;
while (!it1->IsDone()) {
std::cout << it1->CurrentItem() << " 请买车票!" << std::endl;
it1->Next();
}
std::cout << std::endl;
// 产生从后往前的迭代器
Iterator* it2 = a->CreateIteratorDesc();
// 告知每一位乘客买票
std::cout << "从后往前的迭代器:" << std::endl << std::endl;
while (!it2->IsDone()) {
std::cout << it2->CurrentItem() << " 请买车票!" << std::endl;
it2->Next();
}
std::cout << std::endl << std::endl;
delete a, it1, it2;
return 0;
}
单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保护它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。使用单例模式,只能保证一个线程内对象不会被多次创建,而不能保证多线程的情况。因此,需要考虑多线程的话,就要用锁。
看一个只能实例化一个对象的类:
#include
#include
class Singleton {
private:
static Singleton* instance;
// 临界区,防止多线程产生多个实例
static CRITICAL_SECTION m_Sec;
Singleton() {}
public:
static CRITICAL_SECTION* getLock() {
return &m_Sec;
}
static Singleton *GetInstance() {
// 双重锁定
if (instance == NULL) {
EnterCriticalSection(&m_Sec);
if (instance == NULL)
instance = new Singleton();
LeaveCriticalSection(&m_Sec);
}
return instance;
}
};
// 静态成员在类体外定义
Singleton* Singleton::instance = 0;
CRITICAL_SECTION Singleton::m_Sec = CRITICAL_SECTION();
int main(int argc, char const *argv[]) {
// 初始化临界区
InitializeCriticalSection(Singleton::getLock());
Singleton* singleton1=Singleton::GetInstance();
Singleton* singleton2=Singleton::GetInstance();
// 删除临界区
DeleteCriticalSection(Singleton::getLock());
if (singleton1 == singleton2)
std::cout << "两个对象是相同的实例。" << std::endl;
return 0;
}
桥接模式(Bridge),将抽象部分与它的实现部分分离,使它们都可以独立地变化。抽象与它的实现分离,这并不是说让抽象类与其派生类分离,因为这没有任何意义。实现指的是抽象类与它的派生类用来实现自己的对象。为什么要优先使用合成/聚合原则?(1)对象的继承关系是在编译时就定义好了的,所以无法在运行时改变从父类继承的实现,子类的实现与它的父类有非常紧密的依赖关系,以至于父类实现的任何变化必然会导致子类发生变化,当你需要复用子类时,如果继承下来的实现不适合解决新的问题,则父类必须重写或被其它更适合的类替换,这种依赖关系限制了灵活性并最终限制了复用性;(2)优先使用合成/聚合原则有助于保持每个类被封装,并被集中在单个任务上。这样类和类继承层次会保持较小规模,并且不太可能增长为不可控制的庞然大物。盲目使用继承会造成麻烦,本质原因是什么?继承是一种强耦合的结构,父类变,子类就必须要变,所以在用继承时,一定要在是“is-a”的关系时再考虑使用,而不是任何时候都去使用。
如上所示的图中,有一个聚合线,像一座桥,所以叫“桥接模式”。看一个例子,手机品牌类和手机软件类:
#include
#include
#include
// Implementor:此处为手机软件抽象类
class HandsetSoft {
public:
virtual void Run() = 0;
};
// ConcreteImplementorA,此处为手机游戏
class HandsetGame : public HandsetSoft {
void Run() {
std::cout << "运行手机游戏" << std::endl;
}
};
// ConcreteImplementorB,此处为手机通讯录
class HandsetAddressList : public HandsetSoft {
void Run() {
std::cout << "运行手机通讯录" << std::endl;
}
};
// Abstraction,此处为手机品牌抽象类
class HandsetBrand {
protected:
HandsetSoft* soft;
public:
void SetHandsetSoft(HandsetSoft* soft) {
this->soft = soft;
}
virtual void Run() = 0;
};
// RefineAbstraction,此处为手机品N
class HandsetBrandN : public HandsetBrand {
public:
void Run() {
soft->Run();
}
};
// RefineAbstraction,此处为手机品M
class HandsetBrandM : public HandsetBrand {
public:
void Run() {
soft->Run();
}
};
int main(int argc, char const *argv[]) {
// 手机品牌N
std::cout << "手机品牌N:" << std::endl;
HandsetBrand* ab = new HandsetBrandN();
ab->SetHandsetSoft(new HandsetGame());
ab->Run();
ab->SetHandsetSoft(new HandsetAddressList());
ab->Run();
delete ab;
// 手机品牌M
std::cout << std::endl << "手机品牌M:" << std::endl;
ab = new HandsetBrandM();
ab->SetHandsetSoft(new HandsetGame());
ab->Run();
ab->SetHandsetSoft(new HandsetAddressList());
ab->Run();
delete ab;
ab = NULL;
std::cout << std::endl;
return 0;
}
命令模式(Command),将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求进行排队或记录请求日志,以及支持可撤销的操作。命令模式的作用:(1)命令模式能够较容易地设计一个命令队列;(2)在需要的情况下,可以较容易地将命令记入日志;(3)允许接收请求的一方决定是否要否决请求;(4)可以容易地实现对请求的撤销和重做;(5)由于加进新的具体命令类不影响其他的类,因此增加新的具体命令类很容易;(6)命令模式把请求一个操作的对象与知道怎么执行一个操作的对象分隔开。
Command类用来声明执行操作的接口;ConcreteCommand类将一个接收者对象绑定与一个动作,调用接收者相应的操作,以实现Excute;Invoker类要求该命令执行这个请求;Receiver类知道如何实施与执行一个与请求相关的操作,任何类都可能作为一个接收者。看一个例子,通过服务员通知烧烤师傅顾客的菜单:
#include
#include
#include
#include
// Receiver:此处为烤羊肉串者
class Barbecuer {
public:
void BakeMutton() {
std::cout << "烤羊肉串!" << std::endl;
}
void BakeChickenWing() {
std::cout << "烤鸡翅!" << std::endl;
}
};
// Command类,抽象命令
class Command {
protected:
Barbecuer* receiver;
public:
Command(Barbecuer* receiver) {
this->receiver = receiver;
}
virtual void ExcuteCommand() = 0;
};
// ConcreteCommand类,具体命令
class BakeMuttonCommand : public Command {
public:
BakeMuttonCommand(Barbecuer* receiver) : Command(receiver) {}
void ExcuteCommand() {
receiver->BakeMutton();
}
};
// ConcreteCommand类,具体命令
class BakeChickenWingCommand : public Command {
public:
BakeChickenWingCommand(Barbecuer* receiver) : Command(receiver) {}
void ExcuteCommand() {
receiver->BakeChickenWing();
}
};
// Invoker:此处为Waiter服务员
class Waiter {
private:
std::vector<Command*> *orders;
public:
Waiter() {
orders = new std::vector<Command*>;
}
~Waiter() {
delete orders;
}
// 设置订单
void SetOrder(Command* command) {
// 判断命令的类型并分别做不同的处理
if (typeid(*command) == typeid(BakeChickenWingCommand)) {
std::cout << "日志:服务员:鸡翅没有了,请点别的烧烤!" << std::endl;
} else if (typeid(*command) == typeid(BakeMuttonCommand)) {
orders->push_back(command);
time_t now = time(0);
std::cout << "日志:增加订单:命令模式.烤羊肉串 " << "时间:" << asctime(gmtime(&now));
} else {
std::cout << "日志:暂时没有该服务!" << std::endl;
}
}
// 通知全部执行
void Notify() {
std::vector<Command*>::iterator it;
for (it = orders->begin(); it != orders->end(); it++) {
(*it)->ExcuteCommand();
}
}
};
int main(int argc, char const *argv[]) {
// 开店前的准备
Barbecuer* boy = new Barbecuer();
Command* bakeMuttonCommand1 = new BakeMuttonCommand(boy);
Command* bakeMuttonCommand2 = new BakeMuttonCommand(boy);
Command* bakeChickenWingCommand1 = new BakeChickenWingCommand(boy);
Waiter* girl = new Waiter();
// 开门营业,顾客点菜
girl->SetOrder(bakeMuttonCommand1);
girl->SetOrder(bakeMuttonCommand2);
girl->SetOrder(bakeChickenWingCommand1);
// 点菜完毕,通知厨房
girl->Notify();
delete boy, bakeMuttonCommand1, bakeMuttonCommand2, bakeChickenWingCommand1;
return 0;
}
职责链模式(Chain Of Responsibility),使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。职责链模式的好处:(1)最关键的是,当客户提交一个请求时,请求时沿链传递直至有一个ConcreteHandler对象负责处理它;(2)接收者和发送者都没有对方的明确信息,且链中的对象自己也并不知道链的结构,结果是职责链可简化对象的相互连接,它们仅需要保持一个指向其后继者的引用,而不需要保持它所有的候选接收者的引用;(3)由于是在客户端来定义链的结构,所以用户可以随时地增加或者修改处理一个请求的结构,增强了给对象指派职责的灵活性。注意,一个请求极有可能到了链的末端都得不到处理,或者因为没有正确配置而得不到处理。
Handler类定义一个处理请求的接口;ConcreteHandler类是具体的处理请求的接口。看一个向上级请假和加薪的例子:
#include
#include
#include
// 请求类
class Request {
private:
// 请求的类型、内容、数量
std::string requestType;
std::string requestContent;
int number;
public:
void SetType(std::string type) {
this->requestType = type;
}
std::string GetType() {
return requestType;
}
void SetContent(std::string content) {
this->requestContent = content;
}
std::string GetContent() {
return requestContent;
}
void SetNumber(int number) {
this->number = number;
}
int GetNumber() {
return this->number;
}
};
// Handler类,此处为Manager类
class Manager {
protected:
std::string name;
Manager* superior;
public:
Manager() {}
Manager(std::string name) {
this->name = name;
superior = NULL;
}
~Manager() {
if (superior != NULL)
delete superior;
}
// 设置继任者
void SetSuperior(Manager* superior) {
this->superior = superior;
}
// 处理请求的抽象方法
virtual void RequestApplication(Request* request) {};
};
// ConcreteHandler1:此处为经理,CommonManager
class CommonManager : public Manager {
public:
CommonManager(std::string name) : Manager(name) {}
void RequestApplication(Request* request) {
if (request->GetType() == "请假" && request->GetNumber() <= 2) {
std::cout << name << ":" << request->GetContent() << " 数量:" << request->GetNumber() << " 被批准" << std::endl;
} else { // 自己处理不了,转移到下一位进行处理。
if (superior != NULL) {
superior->RequestApplication(request);
}
}
}
};
// ConcreteHandler2:此处为总监,Majordomo
class Majordomo : public Manager {
public:
Majordomo(std::string name) : Manager(name) {}
void RequestApplication(Request* request) {
if (request->GetType() == "请假" && request->GetNumber() <= 5) {
std::cout << name << ":" << request->GetContent() << " 数量:" << request->GetNumber() << " 被批准" << std::endl;
} else { // 自己处理不了,转移到下一位进行处理。
if (superior != NULL) {
superior->RequestApplication(request);
}
}
}
};
// ConcreteHandler3:此处为总经理,GeneralManager
class GeneralManager : public Manager {
public:
GeneralManager(std::string name) : Manager(name) {}
void RequestApplication(Request* request) {
if (request->GetType() == "请假") {
std::cout << name << ":" << request->GetContent() << " 数量:" << request->GetNumber() << " 被批准" << std::endl;
} else if (request->GetType() == "加薪" && request->GetNumber() <= 500) {
std::cout << name << ":" << request->GetContent() << " 数量:" << request->GetNumber() << " 被批准" << std::endl;
} else if (request->GetType() == "加薪" && request->GetNumber() > 500) {
std::cout << name << ":" << request->GetContent() << " 数量:" << request->GetNumber() << " 再说吧" << std::endl;
}
}
};
int main(int argc, char const *argv[]) {
Manager* jinli = new CommonManager("金利");
Manager* zongjian = new Majordomo("宗剑");
Manager* zhongjingli = new GeneralManager("钟精励");
// 设置上级,完全可以按照实际需求来进行更改
jinli->SetSuperior(zongjian);
zongjian->SetSuperior(zhongjingli);
// 下面是4个请求
// 请求1:请假1天
Request request1;
request1.SetType("请假");
request1.SetContent("小菜请假");
request1.SetNumber(1);
// 客户端的申请都是由“经理”发起,但实际谁来决策由具体管理类来处理,客户端不知道
jinli->RequestApplication(&request1);
// 请求2:请假4天
Request request2;
request2.SetType("请假");
request2.SetContent("小菜请假");
request2.SetNumber(4);
// 客户端的申请都是由“经理”发起,但实际谁来决策由具体管理类来处理,客户端不知道
jinli->RequestApplication(&request2);
// 请求3:加薪500元
Request request3;
request3.SetType("加薪");
request3.SetContent("小菜请求加薪");
request3.SetNumber(500);
// 客户端的申请都是由“经理”发起,但实际谁来决策由具体管理类来处理,客户端不知道
jinli->RequestApplication(&request3);
//请求4:加薪1000元
Request request4;
request4.SetType("加薪");
request4.SetContent("小菜请求加薪");
request4.SetNumber(1000);
// 客户端的申请都是由“经理”发起,但实际谁来决策由具体管理类来处理,客户端不知道
jinli->RequestApplication(&request4);
delete jinli, zongjian, zhongjingli;
return 0;
}
中介者模式(Mediator),用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式的优点:(1)Mediator的出现减少了各个Colleague的耦合,使得可以独立地改变和复用各个Colleague,比如任何国家的改变不会影响到其他国家,而只是与安理会发生变化;(2)由于把对象如何协作进行了抽象,将中介作为一个独立的概念并将其封装起在一个对象中,这样关注的对象就从对象各自本身的行为转移到他们之间的交互上来,也就是站在一个更宏观的角度去看待系统。中介者模式的缺点:由于ConcreteMediator控制了集中化,于是就把交互复杂性变为了中介者的复杂性,这就使得中介者会变得比任何一个ConcreteColleague都复杂。中介者模式的用途:中介者模式一般应用于一组对象以定义良好但是复杂的方式进行通信的场合,以及想定制一个分布在多个类中的行为,而又不想生成太多的子类的场合。
Colleague是抽象同事类;ConcreteClleague是具体同事类,每个具体同事只知道自己的行为,而不了解其它同事类的情况,但它们却都认识中介者对象;Mediator是抽象中介者,定义了同事对象到中介者对象的接口;ConcreteMediator是具体中介者对象,实现抽象类的方法,它需要知道所有具体同事类,并从具体同事接收消息,向具体同事对象发出命令。看一个联合国做中介者的例子:
#include
using namespace std;
class Country;
// Mediator
class UnitedNations {
public:
virtual void setColleague1(Country* c) = 0;
virtual void setColleague2(Country* c) = 0;
virtual void Declare(string message, Country* colleague) = 0;
};
// ConcreteMediator
class UnitedNationsSecurityCouncil : public UnitedNations {
private:
Country* colleague1;
Country* colleague2;
public:
void setColleague1(Country* c) {
this->colleague1 = c;
}
void setColleague2(Country* c) {
this->colleague2 = c;
}
void Declare(string message, Country* colleague) {
if (colleague == this->colleague1) {
colleague2->GetMessage(message);
} else {
colleague1->GetMessage(message);
}
}
};
// Colleague
class Country {
protected:
UnitedNations* mediator;
public:
/*Country(UnitedNations* m) {
this->mediator=m;
}*/
virtual void Declare(string message) = 0;
virtual void GetMessage(string message) = 0;
};
// ConcreteColleague
class USA : public Country {
public:
USA(UnitedNations* m) {
this->mediator = m;
}
void Declare(string message) {
mediator->Declare(message, this);
}
void GetMessage(string message) {
cout << "美国获得对方信息:" << message << endl;
}
};
// ConcreteColleague
class Iraq : public Country {
public:
Iraq(UnitedNations* m) {
this->mediator = m;
}
void Declare(string message) {
mediator->Declare(message, this);
}
void GetMessage(string message) {
cout << "伊拉克获得对方信息:" << message << endl;
}
};
享元模式(flyweight),运用共享技术有效地支持大量细粒度的对象,flyweight的意思是轻量级。用享元模式的好处:享元模式可以避免大量非常相似类的开销,在程序设计中,有时需要生成大量细粒度的类实例来表示数据,如果能发现这些实例除了几个参数外基本上都是相同的,有时就能够大幅度的减少需要实例化的类的数量。如果能把那些参数移到类实例的外面,在方法调用时将它们传递进来,就可以通过共享大幅度地减少单个实例的数目,也就是说,享元模式Flyweight执行时所需的状态是有内部的也可能有外部的,内部状态存储于ConcreteFlyweight对象之中,而外部对象则应该考虑由客户端对象存储或计算,当调用Flyweight对象的操作时,将该状态传递给它。什么时候用享元模式?如果一个应用程序使用了大量的对象,而大量的这些对象造成了很大的存储开销时就应该考虑使用;还有就是对象的大多数状态可以外部状态,如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。
Flyweight类是所有具体享元类的超类或接口,通过这个接口,Flyweight可以接受并作用于外部状态;ConcreteFlyweight类继承Flyweight超类或实现Flyweight接口,并为内部状态增加存储空间;UnsharedConcreteFlyweight是指那些不需要共享的Flyweight子类,因为Flyweight接口共享成为可能,但是它并不强制共享;FlyweightFactory是一个享元工厂,用来创建并管理Flyweight对象。它主要是用来确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)。看一个例子,满足不同用户建立不同网站,通过共享减少单个实例的数目,网站:
#include
#include
#include
#include
// 用户类
class User {
private:
std::string name;
public:
User(std::string name) {
this->name = name;
}
std::string GetName() {
return this->name;
}
};
// Flyweight类,此处为抽象网站类
class WebSite {
public:
virtual void Use(User user) = 0;
};
// ConcreteFlyweight类,此处为具体网站类
class ConcreteWebSite : public WebSite {
private:
std::string name;
public:
ConcreteWebSite(std::string name) {
this->name = name;
}
void Use(User user) {
std::cout << "网站分类:" << name << " 用户:"+user.GetName() << std::endl;
}
};
// FlyweightFactory类,此处为网站工程类
class WebSiteFactory {
private:
std::map<std::string,WebSite*> flyweights;
public:
WebSiteFactory() {}
~WebSiteFactory() {
std::map<std::string,WebSite*>::iterator it;
for (it = flyweights.begin(); it != flyweights.end(); it++)
delete it->second;
}
WebSite* GetWebSiteCategory(std::string key) {
std::map<std::string,WebSite*>::iterator it;
for (it = flyweights.begin(); it != flyweights.end(); it++)
if (it->first == key)
return it->second;
WebSite* website = new ConcreteWebSite(key);
flyweights.insert(std::pair<std::string, WebSite*>(key, website));
return website;
}
int GetWebSiteCount() {
return flyweights.size();
}
};
int main(int argc, char const *argv[]) {
WebSiteFactory f;
WebSite* fx = f.GetWebSiteCategory("产品展示");
fx->Use(User("小菜"));
WebSite* fy = f.GetWebSiteCategory("产品展示");
fy->Use(User("大鸟"));
WebSite* fz = f.GetWebSiteCategory("产品展示");
fz->Use(User("娇娇"));
WebSite* fl = f.GetWebSiteCategory("博客");
fl->Use(User("老顽童"));
WebSite* fm = f.GetWebSiteCategory("博客");
fm->Use(User("桃谷六仙"));
WebSite* fn = f.GetWebSiteCategory("博客");
fn->Use(User("南海鳄神"));
std::cout << "得到网站分类总数:" << f.GetWebSiteCount() << std::endl;
return 0;
}
解释器模式(interpreter),给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。解释器模式需要解决的问题:如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子,这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。什么时候用解释器模式?通常当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。用解释器模式的好处:用了解释器模式,就意味着可以很容易地改变和扩展文法,因为该模式使用类来表示文法规则,你可使用继承来改变或扩展该文法,也比较容易实现文法,因为定义抽象语法树种各个节点的类的实现大体类似,这些类都易于直接边写。用解释器模式的不足:解释器模式为文法中的每一条规则至少定义了一个类,因此包含许多规则的文法可能难以管理和维护。建议当文法非常复杂时,使用其他的技术如语法分析程序或编译器生成器来处理。
AbstractExpression(抽象表达式)声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享;TerminalExpression(终结符表达式)实现与文法中的终结符相关联的解释操作,实现抽象表达式中所要求的接口,主要是一个interpreter()
方法。文法中每一个终结符都有一个具体终结表达式与之相对应;NonterminalExpression(非终结符表达式)为文法中的非终结符实现解释操作;Context包含解释器之外的一些全局信息。看一个音乐解释器的例子:
#include
#include
#include
#include
#include
using namespace std;
// Context,此处为演奏内容类
class PlayContext {
private:
std::string text;
public:
void SetText(std::string text) {
this->text = text;
}
std::string GetText() {
return this->text;
}
};
// AbstractExpression,此处为表达式类
class Expression {
public:
void Interpret(PlayContext* context) {
std::string s1 = context->GetText();
std::string buf;
std::string s2;
if(context->GetText().length() == 0) {
return;
} else {
std::vector<std::string> vec;
std::stringstream ss(context->GetText());
while(ss >> buf)
vec.push_back(buf);
std::string playKey = vec[0];
std::string playValue = vec[1];
Excute(playKey, playValue);
vec.erase(vec.begin(), vec.begin() + 2);
std::vector<std::string>::iterator it;
for (it = vec.begin(); it != vec.end(); it++) {
s2 += *it;
if (it != vec.end() - 1)
s2 += " ";
}
context->SetText(s2);
}
}
virtual void Excute(std::string key, std::string value) = 0;
};
// ConcreteExpression,此处为音符类
class Note : public Expression {
public:
void Excute(std::string key, std::string value) {
std::string note;
switch(key[0]) {
case 'C':
note = "1";
break;
case 'D':
note = "2";
break;
case 'E':
note = "3";
break;
case 'F':
note = "4";
break;
case 'G':
note = "5";
break;
case 'A':
note = "6";
break;
case 'B':
note = "7";
break;
}
std::cout << note << " ";
}
};
// ConcreteExpression,此处为音阶类
class Scale : public Expression {
public:
void Excute(std::string key, std::string value) {
std::string scale;
switch(value[0]) {
case '1':
scale = "低音";
break;
case '2':
scale = "中音";
break;
case'3':
scale = "高音";
break;
}
std::cout << scale << " ";
}
};
int main(int argc, char const *argv[]) {
PlayContext context;
std::cout< < "上海滩:" << std::endl;
context.SetText("O 2 E 0.5 G 0.5 A 3 E 0.5 G 0.5 D 3 E 0.5 G 0.5 A 0.5 O 3 C 1 O 2 A 0.5 G 1 C 0.5 E 0.5 D 3");
Expression* expression;
while (context.GetText().length() > 0) {
char c = context.GetText()[0];
switch(c) {
case 'O':
expression = new Scale();
break;
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'A':
case 'B':
case 'P':
expression = new Note();
break;
}
expression->Interpret(&context);
delete expression;
}
return 0;
}
访问者模式(Visitor),表示一个作用于某对象结构中的各元素的操作,它是你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。(1)访问者模式适用于数据结构相对稳定的系统,它把数据结构和作用于数据结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化;(2)访问者模式的目的是要把处理从数据结构分离出来,很多系统可以按照算法和数据机构分开,如果这样的系统有比较稳定的数据结构,又有易于变化的算法的话,使用访问者模式就是比较合适的,因为访问者模式使得算法操作的增加变得容易,反之,如果这样的系统的数据结构对象易于变化,经常要有新的数据对象增加进来,就不适合使用访问者模式;(3)访问者模式的优点:增加新的操作很容易,因为增加新的操作就意味着增加一个新的访问者,访问者模式将有关的行为集中到一个访问者对象中;(4)访问者模式的缺点:使得增加新的数据结构变得困难了;(5)GoF四人中的一人说过:“大多数时候你并不需要访问者模式,但当一旦你需要访问者模式时,那就是真的需要它了”。
Visitor类为该对象结构中ConcreteElement的每一个类声明一个Visit操作;ConcreteVisitor类是具体访问者,实现每个由Visitor声明的操作;Element类定义一个Accept操作,它以一个访问者为参数;ConcreteElementA类是具体元素,实现Accept操作;ObjectStructure类能枚举它的元素,可以提供一个高层的接口以允许访问者访问它的元素。看一个男人和女人的例子:
#include
#include
#include
#include
#include
class Action {
public:
virtual void GetManConclusion(Person* concreteElementA) {};
virtual void GetWomanConclusion(Person* concreteElementB) {};
};
class Success : public Action {
public:
void GetManConclusion(Person* concreteElementA) {
std::cout << typeid(*concreteElementA).name() << " " << typeid(*this).name() << " " << "时,背后多半有一个伟大的女人。" << std::endl;
}
void GetWomanConclusion(Person* concreteElementB) {
std::cout << typeid(*concreteElementA).name() << " " << typeid(*this).name() << " " << "时,背后多半有一个不成功的男人。" << std::endl;
}
};
class Failing : public Action {
public:
void GetManConclusion(Person* concreteElementA) {
std::cout << typeid(*concreteElementA).name() << " " << typeid(*this).name() << " " << "时,闷头喝酒,谁也不用劝。" << std::endl;
}
void GetWomanConclusion(Person* concreteElementB) {
std::cout << typeid(*concreteElementA).name() << " " << typeid(*this).name() << " " << "时,眼泪汪汪,谁也劝不了。" << std::endl;
}
};
class Amativeness : public Action {
public:
void GetManConclusion(Person* concreteElementA) {
std::cout << typeid(*concreteElementA).name() << " " << typeid(*this).name() << " " << "时,凡事不懂也要装懂。" << std::endl;
}
void GetWomanConclusion(Person* concreteElementB) {
std::cout << typeid(*concreteElementA).name() << " " << typeid(*this).name() << " " << "时,遇事懂也装作不懂。" << std::endl;
}
};
class Person {
public:
virtual void Accept(Action* visitor) {};
};
class Man : public Person {
void Accept(Action* visitor) {
visitor->GetManConclusion(this);
}
};
class Woman : public Person {
void Accept(Action* visitor) {
visitor->GetWomanConclusion(this);
}
};
class ObjectStructure {
private:
std::vector<Person*> elements;
public:
ObjectStructure() {}
~ObjectStructure() {
std::vector<Person* >::iterator it;
for (it = elements.begin(); it != elements.end(); it++)
delete *it;
}
void Attach(Person*) {
elements.push_back(element);
}
void Detach(Person*) {
}
void Display(Action*) {
std::vector<Person* >::iterator it;
for (it = elements.begin(); it != elements.end(); it++)
(*it)->Accept(visitor);
}
};
int main(int argc, char const *argv[]) {
ObjectStructure o;
o.Attach(new Man());
o.Attach(new Woman());
Success v1;
o.Display(&v1);
Failing v2;
o.Display(&v2);
Amativeness v3;
o.Display(&v3);
return 0;
}