最近看《深入浅出设计模式》,记录一下学习经验,也分享给和我一样的初学者,书中举了一个例子,假设现在有一家饮料店,销售各种各样的饮料,比如饮料:咖啡,牛奶,汽水等等,而这些饮料还可以和不同的调料进行组合,产生新的饮料,比如调料:冰、奶糖、果冻等。该模式的优点在于,当饮料店增加新的饮料和配料时,可以在不改动之前的源码的基础上进行扩展,及设计模式中的要点:对扩展开放,对修改关闭。
咋们先看看类图:
接下来看看源码:
#include <iostream>
#include <string>
using namespace std;
//饮料
class Beverage
{
public:
string description;
Beverage(): description("Unknow Beverage")
{
cout << "Create Beverage" << endl;
}
virtual ~Beverage()
{
cout << "Delete Beverage" << endl;
}
virtual int cost() = 0;
virtual string getDescription() = 0;
};
//佐料装饰类
class CondimentDecorator : public Beverage
{
public:
CondimentDecorator()
{
cout << "Create CondimentDecorator" << endl;
}
virtual ~CondimentDecorator()
{
cout << "Delete CondimentDecorator" << endl;
}
virtual int cost() = 0;
virtual string getDescription() = 0;
};
//一种具体的饮料
class Milk : public Beverage
{
public:
Milk()
{
description = "Milk";
cout << "Create Milk" << endl;
}
~Milk()
{
cout << "Delete Milk" << endl;
}
string getDescription()
{
return description;
}
int cost()
{
return 2;
}
};
//牛奶装饰佐料
class Ice : public CondimentDecorator
{
public:
Ice(Beverage *beverage)
{
this->beverage = beverage;
cout << "Create Ice" << endl;
}
~Ice()
{
cout << "Delete Ice" << endl;
};
int cost()
{
return 1 + beverage->cost();
}
string getDescription()
{
return beverage->description + "Ice";
}
Beverage *beverage;
};
int main()
{
int i = 0;
Beverage *beverageHouseBlend = NULL;
Beverage *beverage = new Milk;
beverageHouseBlend = beverage;
beverage = new Ice(beverage); //牛奶里加冰
cout << beverage->getDescription() + ": " << beverage->cost() << endl;
delete beverage;
delete beverageHouseBlend;
cin >> i;
return 0;
}
很少使用C++实际编程,编写这里例子的时候遇到了一些麻烦,和大家分享一下其中 的一些C++概念。
1、虚函数与纯虚函数:
virtual ~Beverage(){}//虚函数
virtual int cost() = 0; //纯虚函数
通俗的区别,虚函数需要实现函数体,而纯虚函数不需要实现函数体,进而在继承基类时,派生类必须重写纯虚函数,可以不重新虚函数,直接使用父类的虚函数。
2、构造函数不能为虚函数:
虚函数的意思就是开启动态绑定,在调用构造函数时,对应的对象还未完全创建,无法进行动态绑定,因此构造函数不能为虚函数。
3、基类的析构函数为虚函数:
当我们使用基类指针释放派生类时,才能调用正确的析构函数。
4、派生类初始化列表无法初始化基类成员变量
因为在“初始化列表”中初始化成员变量时,此时还没有调用基类的构造函数,也就是说基类还未完成创建,因此想在派生类构造时改变基类变量值,就只有在派生类的构造函数中赋值了。
5、构造与析构顺序
从图中,我们可以看出,在构造时,在创建一个派生类对象时,需要先构造它的父类对象,在析构一个派生类对象时,最后析构父类对象。