常用设计模式这样学

简介: 常用设计模式这样学

  如果你也跟笔者一样,初学模式的时候,20多种设计模式让你眼花缭乱,不知道如何下手,可以试试这里提出的方法。无论面试,或者重构代码的时候,都能知道相应设计模式的使用场景。简而言之,就是案例记忆法。通过记住每个设计模式的典型案例,达到对常用的几个设计模式了然于胸的境界。这里列举常用的5种设计模式,一般面试和简单的使用场景均能覆盖。如果希望掌握全部的设计模式,可以用这种方法总结剩下的模式。

模板方法模式 – 动物园表演流程

  模板模式的关键词是,流程固定。这个设计模式适合流程固定的情况。比如动物园的表演流程有5个步骤(稳定点),其中某些步骤的表演内容需要改变(变化点)。

class ZooShow {
public:
    // 固定流程封装到这里
    void Show() {
        Show0();
        Show1();
        Show2();
        Show3();
    }
protected:
    // 子流程 使用protected保护起来 不被客户调用 但允许子类扩展
    virtual void Show0(){
        cout << "show0" << endl;
    }
    virtual void Show2(){
        cout << "show2" << endl;
    }
    virtual void Show1() {
    }
    virtual void Show3() {
    }
};
// 通过继承生成不同的派生类,来达到修改某个流程的目的
class ZooShowEx1 : public ZooShow {
protected:
    virtual void Show0(){
        cout << "show1" << endl;
    }
    virtual void Show2(){
        cout << "show3" << endl;
    }
};
class ZooShowEx2 : public ZooShow {
protected:
    virtual void Show1(){
        cout << "show1" << endl;
    }
    virtual void Show2(){
        cout << "show3" << endl;
    }
};
// 反向调用,框架是固定的,仅可复写不同的show()子函数
int main () {
    ZooShow *zs1 = new ZooShowEx1;
    ZooShow *zs2 = new ZooShowEx2;
    zs1->Show();
    return 0;
}

观察者模式 – 数据中心显示

  观察者模式,或者称之为发布/订阅模式,关键词是组装(attach)和拆卸(detach)。比如数据中心需要发送同一种数据(稳定点)到不同的显示终端显示,可以增加新的显示终端,可以删除旧的显示终端(变化点)。

// 不同的显示终端定义统一接口
class IDisplay {
public:
    virtual void Show(float temperature) = 0;
    virtual ~IDisplay() {}
};
// 根据接口定义出一系列显示终端
class DisplayA : public IDisplay {
public:
    virtual void Show(float temperature);
};
class DisplayB : public IDisplay{
public:
    virtual void Show(float temperature);
};
class WeatherData {
};
// 数据中心提供组装和拆卸显示终端的接口
class DataCenter {
public:
    void Attach(IDisplay * ob);
    void Detach(IDisplay * ob);
    void Notify() {
        float temper = CalcTemperature();
        for (auto iter = obs.begin(); iter != obs.end(); iter++) {
            (*iter)->Show(temper);
        }
    }
private:
    virtual WeatherData * GetWeatherData();
    virtual float CalcTemperature() {
        WeatherData * data = GetWeatherData();
        // ...
        float temper/* = */;
        return temper;
    }
    std::vector<IDisplay*> obs;
};
// 具体使用
int main() {
    DataCenter *center = new DataCenter;
    IDisplay *da = new DisplayA();
    IDisplay *db = new DisplayB();
    center->Attach(da);
    center->Attach(db);
    center->Notify();
    // 增加新的/删除旧的显示终端
    center->Detach(db);
    center->Notify();
    return 0;
}

策略模式 – 节日促销策略

  策略模式的关键词是策略批量化。比如不同的节日做不同的促销活动。策略批量化就是每一种节日有一份自己的促销策略,用节日策略去构造促销对象。做促销本身是稳定的(即根据不同的节日有对应的促销活动),节日是变化的(可以有不同类型的节日),具体实现促销的方式也是变化的。

class ProStategy {
public:
    virtual double CalcPro(const Context &ctx) = 0;
    virtual ~ProStategy();
};
//策略批量化:
// 1.cpp
class VAC_Spring : public ProStategy {
public:
    virtual double CalcPro(const Context &ctx){}
};
// 2.cpp
class VAC_Wuyi : public ProStategy {
public:
    virtual double CalcPro(const Context &ctx){}
};
// 节日策略组合进促销策略类
class Promotion {
public:
    Promotion(ProStategy *sss) : s(sss){}
    ~Promotion(){}
    double CalcPromotion(const Context &ctx){
        return s->CalcPro(ctx);
    }
private:
    ProStategy *s;
};
// 用节日策略去构造促销对象
int main () {
    Context ctx;
    ProStategy *s = new VAC_QiXi1();
    Promotion *p = new Promotion(s);
    p->CalcPromotion(ctx);
    return 0;
}

责任链模式 – 请假流程

  责任链模式用一句话替代,仅链条中的某一环有责任处理。比如请假流程,1天内是主管批准,3天内需要项目经理批准,3天以上老板批准。

class Context {
public:
    std::string name;
    int day;
};
// 定义一个处理接口
class IHandler {
public:
    virtual ~IHandler() {}
    void SetNextHandler(IHandler *next) {
        next = next;
    }
    bool Handle(ctx) {
        if (CanHandle(ctx)) {
            return HandleRequest();
        } else if (GetNextHandler()) {
            return GetNextHandler()->HandleRequest(ctx);
        } else {
            // err
        }
    }
protected:
    virtual bool HandleRequest(const Context &ctx) = 0;
    virtual bool CanHandle(const Context &ctx) =0;
    IHandler * GetNextHandler() {
        return next;
    }
private:
    IHandler *next;
};
// 根据接口批量化生产一系列处理环节
class HandleByMainProgram : public IHandler {
protected:
    virtual bool HandleRequest(const Context &ctx){
    }
    virtual bool CanHandle() {
    }
};
class HandleByProjMgr : public IHandler {
protected:
    virtual bool HandleRequest(const Context &ctx){
    }
    virtual bool CanHandle() {
    }
};
class HandleByBoss : public IHandler {
public:
    virtual bool HandleRequest(const Context &ctx){
    }
protected:
    virtual bool CanHandle() {
    }
};
// 使用方式
int main () {
    IHandler * h1 = new MainProgram();
    IHandler * h2 = new HandleByProjMgr();
    IHandler * h3 = new HandleByBoss();
    h1->SetNextHandler(h2);
    Context ctx;
    h1->handle(ctx);
    return 0;
}

装饰器模式 – 公司奖金

  装饰器模式的关键词是,一种功能作为一种装饰器,动态组合。对应的案例就是公司奖金,普通员工有销售奖金,累计奖金等。部门经理还有团队奖金。可能还会增加新人奖,老人奖,年度奖等等。

class Context {
public:
    bool isMgr;
    // User user;
    // double groupsale;
};
// 试着从职责出发,将职责抽象出来
class CalcBonus {    
public:
    CalcBonus(CalcBonus * c = nullptr) {}
    virtual double Calc(Context &ctx) {
        return 0.0; // 基本工资
    }
    virtual ~CalcBonus() {}
protected:
    CalcBonus* cc;
};
class CalcMonthBonus : public CalcBonus {
public:
    CalcMonthBonus(CalcBonus * c) : cc(c) {}
    virtual double Calc(Context &ctx) {
        double mbonus /*= 计算流程忽略*/; 
        return mbonus + cc->Calc(ctx);
    }
};
class CalcSumBonus : public CalcBonus {
public:
    CalcSumBonus(CalcBonus * c) : cc(c) {}
    virtual double Calc(Context &ctx) {
        double sbonus /*= 计算流程忽略*/; 
        return sbonus + cc->Calc(ctx);
    }
};
class CalcGroupBonus : public CalcBonus {
public:
    CalcGroupBonus(CalcBonus * c) : cc(c) {}
    virtual double Calc(Context &ctx) {
        double gbnonus /*= 计算流程忽略*/; 
        return gbnonus + cc->Calc(ctx);
    }
};
class CalcCycleBonus : public CalcBonus {
public:
    CalcGroupBonus(CalcBonus * c) : cc(c) {}
    virtual double Calc(Context &ctx) {
        double gbnonus /*= 计算流程忽略*/; 
        return gbnonus + cc->Calc(ctx);
    }
};
// 计算方式为,把一种装饰器作为参数构造成另一个装饰器,动态组合后即为某种类型的员工全部奖金
int main() {
    // 1. 普通员工
    Context ctx1;
    CalcBonus *base = new CalcBonus();
    CalcBonus *cb1 = new CalcMonthBonus(base);
    CalcBonus *cb2 = new CalcSumBonus(cb1);
    cb2->Calc(ctx1);
    // 2. 部门经理
    Context ctx2;
    CalcBonus *cb3 = new CalcGroupBonus(cb2);
    cb3->Calc(ctx2);
}

  本来准备将工厂方法,抽象工厂,适配器,代理模式一起整理出来,但没有发现特别适合的案例。目前整理的这5种设计模式都是最常用,也最好理解的。此外设计模式的八个原则,什么依赖倒置原则,里式替换原则也要熟记,面试很可能会让背。当然熟悉这几种设计模式也更能理解那些原则。以上。

相关文章
|
设计模式
我所认识的设计模式
我所认识的设计模式
62 0
|
设计模式 容器
2022-9-19-C++各种设计模式的简单总结
2022-9-19-C++各种设计模式的简单总结
79 0
|
设计模式
设计模式——里氏替换
设计模式——里氏替换
|
设计模式 消息中间件 Java
一起来学设计模式之认识设计模式
前言 目前正在出一个设计模式专题系列教程, 篇幅会较多, 喜欢的话,给个关注❤️ ~ 本节给大家讲一下设计模式基本概念,它的基本原则以及有哪些设计模式~ 本专题的所有案例代码主要以Java语言为主, 好了, 废话不多说直接开整吧~ 设计模式初识 设计模式是一种经过验证的、被广泛应用的解决特定问题的软件设计方案,它提供了一种在软件设计中反复使用的解决方案。设计模式通常描述了一个问题的情境、解决方案和解决方案的优点和缺点。设计模式不是一种具体的编程语言特性或库,而是一种通用的设计思想和方法。
|
存储 设计模式 XML
设计模式(六)
设计模式
187 0
|
设计模式
设计模式(3)
设计模式(3)
114 0
|
设计模式 缓存 安全
你知道哪些设计模式
你知道哪些设计模式
141 0
你知道哪些设计模式
|
设计模式 消息中间件 缓存
设计模式也可以这么简单
设计模式是对大家实际工作中写的各种代码进行高层次抽象的总结,其中最出名的当属 Gang of Four (GoF) 的分类了,他们将设计模式分类为 23 种经典的模式,根据用途我们又可以分为三大类,分别为创建型模式、结构型模式和行为型模式。
243 0
设计模式也可以这么简单