在回顾设计模式的时候发现装饰者模式的调用过程在脑子里总是转不过来,于是找了个时间在电脑上调试了下,看了看指针调度过程,怕哪天又转不过来弯,所以记录下来。
话说因为最近环保抓的严,光头强也不能满山遍野秃秃秃了,生活得继续啊,只好改行做了护林员,因此跟二熊结束了“打情骂俏”的日子,开始了“相濡以沫”的生活。
一天在树梢和树下,发生了这样一段对话:
**熊大:**光头强,你说你整天盯着你那破电脑看啥看,还神秘兮兮的,有花吗?
光头强:你个熊憨憨就知道吃,还知道个啥,我那电脑里存的都是好东西。
**熊大:**啥好东西?
**光头强:**知识大片,看一部初窥门径,看两部渐入佳境,时时翻阅才能功力大成!你不懂。
**熊大:**说的恁玄乎,俺都成年了会不懂?不就是少儿不宜的东西嘛,就跟谁不知道一样。
**光头强:**呦,近朱者赤啊,你们跟着我长了不少见识啊。
**熊大:**我们是自学成才,与时俱进。
**光头强:**挺能白活,不过别瞎传,我那不是少儿不宜,是日本特有的有关爱情的动作大片,真是学习观摩,强身健体的。你瞅这名头还看不出来么。
**熊大:**噢噢,听起来是挺厉害。
各位看官们瞅瞅,电脑里存的小电影都被包裹成艺术品了,你说厉害不厉害。就拿电脑来说装饰,往大了说,分不同品牌,外观,CPU,显卡,内存,硬盘。往小了说电脑的各类软件,里面存的各种学习资料,都可算是他的装饰,以下就以上述对话举个例。
一 IComputer就相当于UML的component类(抽象构件),myComputer相当于ConcreteComponent(具体构建)。这两个类不是必须都要有,看需求。
class IComputer
{
public:
virtual void watchMovie() = 0; //看电影 纯虚函数
};
class MyConputer : public IComputer
{
public:
void watchMovie()
{
cout<<"\n真正写实的电影:";
}
};
二 DecoratorMovie抽象装饰类
电脑中保存着电影
class DecoratorMovie : public IComputer
{
public:
DecoratorMovie(IComputer* computer)
:m_computer(computer)
{
}
void watchMovie()
{
m_computer->watchMovie();
movieType();
}
virtual void movieType() = 0; //哪种电影
protected:
IComputer* m_computer;
};
三 具体装饰内容
电影藏的很深,以文艺点的名称作为修饰:日本特有的,有关爱情的,动作大片。一般人找不到(傲娇)
class JaponicMov : public DecoratorMovie
{
public:
JaponicMov(IComputer* computer):DecoratorMovie(computer){};
void movieType()
{
cout<<" 是日本特有的";
}
};
class LoveMov : public DecoratorMovie
{
public:
LoveMov(IComputer* computer):DecoratorMovie(computer){};
void movieType()
{
cout<<" 有关爱情的";
}
};
class ActionMov : public DecoratorMovie
{
public:
ActionMov(IComputer* computer):DecoratorMovie(computer){};
void movieType()
{
cout<<" 动作大片";
}
};
主函数中调用:
分别调用三次是为了更方便看清调用过程,原理都是一样。
IComputer* myComputer = new MyConputer();
JaponicMov* janMov = new JaponicMov(myComputer);
LoveMov* LovMov = new LoveMov(janMov);
ActionMov* actMov = new ActionMov(LovMov);
//调用层级渐次加深
janMov->watchMovie();
LovMov->watchMovie();
actMov->watchMovie();
打印结果为:
上面一二三行为别是
janMov->watchMovie();
LovMov->watchMovie();
actMov->watchMovie();
的调用结果展示。
调试使用的VSCode+WSL,编译用的g++。
以janMov->watchMovie()调用为例进行调试
首先断点打在janMov->watchMovie(),左上角可以看到实例化对象的指针地址,可以清楚的看到myComputer对象的地址为:0x8414e70;janMov的地址为:0x8414e70。
实例化janMov时传入对象myComputer,最终myComputer地址赋值给JaponicMov的父类即抽象装饰类DecoratorMovie的成员变量m_computer。
截图左上角可以看到myComputer与m_computer指向相同的地址。
此时调用janMov->watchMovie()因为子类JaponicMov没有watchMovie()的实现,所以会走到装饰类DecoratorMovie里的成员函数watchMovie(),而watchMovie()里做了两个动作:
m_computer->watchMovie();
movieType();
m_computer->watchMovie()动作会调用MyConputer类watchMovie()的实现,打印:
真正写实的电影:
走进函数里看看就可以验证,点击F11:
发现走进了DecoratorMovie类的watchMovie()。
再次点击:
此时进到了DecoratorMovie类的父类成员函数里。此时就会打印
真正写实的电影:
执行下一步走到watchMovie();
此时虽然在抽象装饰类里,但左上角this指针可以看出指向的是子类,最终会调用子类实现的movieType(),即打印
是日本特有的
。
最终结果:
#include <iostream>
using namespace::std;
class IComputer
{
public:
virtual void watchMovie() = 0; //看电影 纯虚函数
};
class MyConputer : public IComputer
{
public:
void watchMovie()
{
cout<<"\n真正写实的电影:";
}
};
class DecoratorMovie : public IComputer
{
public:
DecoratorMovie(IComputer* computer)
:m_computer(computer)
{
}
void watchMovie()
{
m_computer->watchMovie();
movieType();
}
virtual void movieType() = 0; //哪种电影
protected:
IComputer* m_computer;
};
class JaponicMov : public DecoratorMovie
{
public:
JaponicMov(IComputer* computer):DecoratorMovie(computer){};
void movieType()
{
cout<<" 是日本特有的";
}
};
class LoveMov : public DecoratorMovie
{
public:
LoveMov(IComputer* computer):DecoratorMovie(computer){};
void movieType()
{
cout<<" 有关爱情的";
}
};
class ActionMov : public DecoratorMovie
{
public:
ActionMov(IComputer* computer):DecoratorMovie(computer){};
void movieType()
{
cout<<" 动作大片";
}
};
int main()
{
IComputer* myComputer = new MyConputer();
JaponicMov* janMov = new JaponicMov(myComputer);
LoveMov* LovMov = new LoveMov(janMov);
ActionMov* actMov = new ActionMov(LovMov);
//调用层级渐次加深
janMov->watchMovie();
LovMov->watchMovie();
actMov->watchMovie();
//释放
}