最近在看《Head First 设计模式》,感觉挺有意思的,本系列的多数内容也是引自于它。
不过会加入一些自己的理解,代码肯定也是敲自己的啦~
其实呢,我们在日常编程时或多或少都在使用着设计模式,只是我们没有意思它有那么一个“官方”的名称罢了,
比如下面的“策略模式”就是这样:
策略模式:定义算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
太官方了哈,还是写个测试代码看看:
为了鲜明,我们只保留主要代码,大致意思出来就行~
假设现在有个Person抽象基类,其纯虚函数Language()需要子类重写,由于并不是每个不同人种的Language()都不同(比如英国人和美国人都speak English(不要太较真噢。。。)),所以对每个派生类重写这个方法可能不太合适,那么我们可以考虑将Language()移到一个接口类中来单独声明:
class ILanguage { public: virtual void speak() = 0; }
然后我们可以在Person类中包含这个接口类的指针,为了方便使用,再定义一个speak()函数来调用这个接口的方法:
class Person{ public: ILanguage* iLanguage; void speak(){iLanguage->speak();} }
接着我们使用speak English实现一次接口:
class LanguageEnglish : public ILanguage { public: void speak(){ std::out << "I Can Speak English"; } }
好了,是时候实现我们具体的Person了,先实现一个美国人吧,我们在构造函数中将接口指针初始化,使美国人能够说英语:
class American : public Person { public: American(){ iLanguage = new LanguageEnglish(); } }
写段测试代码看看:
Person *p = new American(); p->speak();
不出意外,我们应该可以看到他说英语了,但是如果他后来又学习了中文呢?
well,我们可以在设计Person类时为它加上一个setLanguage函数,变成下面这样:
class Person{ public: ILanguage* iLanguage; void speak(){iLanguage->speak();} void setLanguage(ILanguage* i){iLanguage = i;} }
然后我们针对ILanguage再实现一个Chinese版本:
class LanguageChinese : public ILanguage { public: void speak(){ std::out << "I Can Speak Chinese"; } }
再测试一下:
Person *p = new American(); p->speak(); p->setLanguage(new LanguageChinese()); p->speak();
可以看到两行不同的输出。
可以在这个设计模式看到三个设计原则:
1、封装变化
由于软件开发过程中迭代的反复性,我们应该将易变的部分独立开来。
2、多用组合,少用继承
使用组合建立系统往往比使用继承具有更大的弹性。
3、针对接口编程,不针对实现编程
接口编程:使用一个接口函数在运行时调用不同的实现;
实现编程:实现代码写在实体类中,弹性差,不灵活。
好,先到这里吧~