(Boolan) C++设计模式 第一周笔记

一、8个重要的设计原则

①依赖倒置原则(DIP)
高层模块(稳定)不应该依赖底层模块(变化),二者都应该依赖于抽象(稳定);抽象不应该依赖于实现细节,实现细节应该依赖抽象。
②开放封闭原则(OCP)
对扩展开放,对更改封闭
类模块应该是可扩展的,但是不可修改。
以扩展的方式应对需求变更。
③单一职责原则(SRP)
一个类应该是仅有一个引起它变化的原因,变化的方向隐含着类的责任。该职责是为避免过于复杂。
④Listov 替换原则(LSP)
子类必须能够替换它们的基类(IS-A)
以继承表达类型抽象
⑤接口隔离原则(ISP)
不应该强迫客户程序依赖它们不用的方法
接口应该小而完备
⑥优先使用对象组合,而不是类继承
类继承通常是“白箱复用”,对象组合通常是“黑箱复用”。
继承在某种程度上破坏了封装性,子类父类耦合度高;而对象组合则只要求被组合的对象具有良好定义的接口,耦合度低。
⑦封装变化点
使用封装来创建对象之间的分界层,让设计着可以在分界层的一侧进行修改,而不会对另一侧产生不良的影响,从而实现层次间的松耦合。
⑧针对接口编程,而不是针对实现编程。
此条与①对应,不将变量类型声明为某个特定的具体类,而是声明为某个接口。客户程序不需获知对象的具体类型,只需知道对象的接口。
减少系统中各部分的依赖关系,从而实现“高内聚、松耦合”的类型设计方案。
接口标准化是产业强盛的标志。
二、策略模式
策略模式
介绍:定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。

类图

策略模式

适用场景:一个系统需要动态地在几种算法中选择一种。
优点:1.策略模式提供了管理相关的算法族的办法。2.策略模式提供了可以替换继承关系的办法。 3.使用策略模式可以避免使用多重条件转移语句。
1、先看看策略模式的官方定义:
The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.(策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。)
策略模式类图如下:


2、《大话设计模式》实现策略模式中,使用到了反射。前面也说过,在C++中实际没有反射,需要自己实现。为实现反射,我模仿MFC中RTTI的dynamic调用,利用链表实现了个简单的反射功能。代码如下:
ReflectionFunc.h

#pragma once  
#include "stdafx.h"  
#include <string>  
#include <map>  
#include <vector>  
using namespace std;  
  
typedef void* (*CreateFunc)();  
  
struct ClassFactory  
{  
    std::string m_strName;  
    CreateFunc m_pObject;  
  
    static void* GetClassByName(std::string strName);  
  
    static ClassFactory* pFirstClass;  
    ClassFactory* m_pNextClass;  
};  
  
struct MY_CLASSINIT  
{   
    MY_CLASSINIT(ClassFactory* pNewClass);   
};  
  
#define DECLARE_MYCLASS(class_name) \  
    static void* CreateObject(class_name);\  
    static ClassFactory m_CF##class_name;  
  
#define IMPLEMENT_MYCLASS(class_name)\  
    static char my##class_name[] = #class_name;\  
    void* class_name::CreateObject(class_name) { return new class_name; }\  
    ClassFactory class_name::m_CF##class_name = {my##class_name, (CreateFunc)class_name::CreateObject};\  
    static MY_CLASSINIT _init_##class_name(&class_name::m_CF##class_name);   
      

ReflectionFunc.cpp

#pragma once  
#include "StdAfx.h"  
#include "ReflectionFunc.h"  
  
ClassFactory* ClassFactory::pFirstClass = NULL;  
  
void* ClassFactory::GetClassByName(std::string strName)  
{  
    void* pObject=NULL;  
    ClassFactory* pClass = pFirstClass;  
    for (;pClass!=NULL;pClass=pClass->m_pNextClass)  
    {  
        if (pClass->m_strName.compare(strName) == 0)  
        {  
            pObject = pClass->m_pObject();  
        }  
    }  
    return pObject;  
}  
  
MY_CLASSINIT::MY_CLASSINIT(ClassFactory* pNewClass)  
{  
    pNewClass->m_pNextClass = ClassFactory::pFirstClass;  
    ClassFactory::pFirstClass = pNewClass;  
}  

3、策略模式的其他部分代码实现如下:
CashContext.h


#pragma once  
#include "StrategyPattern.h"  
#include "CashSuper.h"  
#include <string>  
using namespace std;  
  
class STRATEGYPATTERN_API CCashContext  
{  
public:  
CCashContext(void);  
~CCashContext(void);  
  
void SetBehavior(std::string strClassName, char szParam[]);  
double GetResult(double money);  
  
private:  
CCashSuper* m_pCashSuper;  
};  

CashContext.cpp

#pragma once  
#include "StdAfx.h"  
#include "CashContext.h"  
#include "ReflectionFunc.h"  
  
CCashContext::CCashContext(void)  
{  
  
}  
  
  
CCashContext::~CCashContext(void)  
{  
      
}  
  
void CCashContext::SetBehavior(std::string strClassName, char szParam[])  
{  
    CCashSuper* pCash = (CCashSuper*)ClassFactory::GetClassByName(strClassName);  
    if (!pCash) return;  
    pCash->SetClassParam(szParam);  
    m_pCashSuper = pCash;  
}  
  
double CCashContext::GetResult(double money)  
{  
    return m_pCashSuper->acceptCash(money);  
}  

CashSuper.h

#pragma once  
#include <vector>  
#include "ReflectionFunc.h"  
  
class CCashSuper  
{  
public:  
    CCashSuper(void);  
    ~CCashSuper(void);  
  
    virtual void SetClassParam(const char* pParam)=0;  
    virtual double acceptCash(double money)=0;  
};  

CashRebate.h

#pragma once  
#include "cashsuper.h"  
#include "Utility.h"  
  
class CCashRebate :public CCashSuper  
{  
public:  
    DECLARE_MYCLASS(CCashRebate)  
    CCashRebate(void);  
    ~CCashRebate(void);  
  
    virtual void SetClassParam(const char* pParam);  
    virtual double acceptCash(double money);  
  
private:  
    double m_Rebate;  
};  

CashRebate.cpp

#pragma once  
#include "StdAfx.h"  
#include "CashRebate.h"  
  
IMPLEMENT_MYCLASS(CCashRebate)  
  
CCashRebate::CCashRebate(void)  
{  
    m_Rebate = 1;  
}  
  
  
CCashRebate::~CCashRebate(void)  
{  
}  
  
double CCashRebate::acceptCash(double money)  
{  
    return money * m_Rebate;  
}  
  
void CCashRebate::SetClassParam(const char* pParam)  
{  
    std::string str(pParam);  
    std::vector<string> vecStr;  
    CUtility::GetInstance().SplitString(str, vecStr);  
    m_Rebate = atof(vecStr[0].c_str());  
}  

三、装饰模式
装饰模式
介绍:动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。 *A_Decorator decoratorA = new A_Decorator (new Object1);

类图

装饰者模式

适用场景:需要动态地将功能添加到对象上时,使用装饰者模式。不改变接口但要增强功能。
优点:1.装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。2.可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的装饰器,从而实现不同的行为。

装饰模式:动态的给一个对象添加一些额外的职能。
网上有个说法感觉比较形象(http://zhousenbiao.com/Design-Patterns/decorator.html):
所谓装饰,就是一些对象给主体对象做陪衬。这是我的理解。好比说我的办公桌,需要电脑、电话、文件夹、盆栽等作为装饰。那么,办公桌就是一个主体对象,电脑、电话等装饰品就是那些做陪衬的对象。这些办公用品准备好了,该怎么摆放到办公桌上呢?可以有多种方案。而且,我可以随时往办公桌上增加一支签字笔,增加一枚公章等等。目前,可归纳如下:A主体对象:办公桌B装饰者:电脑、电话、文件夹、盆栽、签字笔、公章C装饰者可以装饰主体对象,即B可以装饰A什么是装饰模式?一个标准的定义是:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比基础更有弹性的替代方案。根据我的理解,装饰模式可以这样定义:能够动态地为对象添加功能,同时不会对类进行修改。

网上还有篇装饰者模式总结得比较好的:http://www.cnblogs.com/god_bless_you/archive/2010/06/10/1755212.html

好了,不多说。C++代码如下:

#include "stdafx.h"  
#include <string>  
#include <iostream>  
using namespace std;  
  
class Person  
{  
public:  
    Person(){}  
    ~Person(){}  
  
    Person(std::string name)  
    {  
        m_strName = name;  
    }  
  
    virtual void Show()  
    {  
        cout<<"装扮的"<<m_strName<<endl;  
    }  
private:  
    std::string m_strName;  
};  
  
class Finery: public Person  
{  
public:  
    Finery(){}  
    ~Finery(){}  
  
    void Decorate(Person* compent)  
    {  
        m_component = compent;  
    }  
  
    void Show()  
    {  
        if (m_component)  
        {  
            m_component->Show();  
        }  
    }  
private:  
    Person* m_component;  
};  
  
class TShirt: public Finery  
{  
public:  
    TShirt(){}  
    ~TShirt(){}  
  
    void Show()  
    {  
        cout<<"T恤 ";  
        Finery::Show();  
    }  
};  
  
class Sneakers: public Finery  
{  
public:  
    Sneakers(){}  
    ~Sneakers(){}  
  
    void Show()  
    {  
        cout<<"破球鞋 ";  
        Finery::Show();  
    }  
};  
  
class Suit : public Finery  
{  
public:  
    Suit(){}  
    ~Suit(){}  
  
    void Show()  
    {  
        cout<<"西装 ";  
        Finery::Show();  
    }  
};  
  
class Tie : public Finery  
{  
public:  
    Tie(){}  
    ~Tie(){}  
  
    void Show()  
    {  
        cout<<"领带 ";  
        Finery::Show();  
    }  
};  
  
int _tmain(int argc, _TCHAR* argv[])  
{  
    Person* person = new Person("小菜");  
    cout<<"第一种装扮:"<<endl;  
    TShirt* tshirt = new TShirt();  
    Tie* tie = new Tie();  
    Suit* suit = new Suit();  
  
    tshirt->Decorate(person);  
    tie->Decorate(tshirt);  
    suit->Decorate(tie);  
  
    suit->Show();  
  
    return 0;  
}  

四、桥模式
1: 桥模式
介绍:将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。

类图

桥模式

适用场景:需要将两组不同的功能组合来用时,可以考虑用“桥”将这两组功能组合起来。
优点:1.分离抽象接口及其实现部分。2.桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统。

五、 观察者模式
介绍:定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式

类图

观察者模式

适用场景:一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
优点:1.观察者模式可以实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。2.观察者模式支持广播通信。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,843评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,538评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,187评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,264评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,289评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,231评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,116评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,945评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,367评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,581评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,754评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,458评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,068评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,692评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,842评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,797评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,654评论 2 354

推荐阅读更多精彩内容