其他分享
首页 > 其他分享> > 设计模式--行为型模式

设计模式--行为型模式

作者:互联网

行为型设计模式,主要如下:

1、迭代器(Iterator)
2、中介者(Mediator)
中介者模式:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显示地相互引用,从而使其耦合松散,而且可以独立地改变它们之前的交互。

如果对象与对象之前存在大量的关联关系,若一个对象改变,常常需要跟踪与之关联的对象,并做出相应的处理,这样势必会造成系统变得复杂,遇到这种情形可以考虑使用中介者模式。当多个对象存在关联关系时,为它们设计一个中介对象,当一个对象改变时,只需要通知它的中介对象,再由它的中介对象通知每个与它相关的对象。

/*
* 关键代码:将相关对象的通信封装到一个类中单独处理。
*/
#include <iostream>
​
using namespace std;
​
class Mediator;
​
//抽象同事类。
class Businessman
{
public:
    Businessman(){}
    Businessman(Mediator* mediator) : m_pMediator(mediator){}
​
    virtual ~Businessman(){}
​
    virtual void setMediator(Mediator* m)
    {
        m_pMediator = m;
    }
​
    virtual void sendMessage(const string& msg) = 0;
    virtual void getMessage(const string& msg) = 0;
​
protected:
    Mediator* m_pMediator;
};
​
//抽象中介者类。
class  Mediator
{
public:
    virtual ~Mediator(){}
    virtual void setBuyer(Businessman* buyer) = 0;
    virtual void setSeller(Businessman* seller) = 0;
    virtual void send(const string& msg, Businessman* man) = 0;
};
​
//具体同事类
class Buyer : public Businessman
{
public:
    Buyer() : Businessman(){}
    Buyer(Mediator* mediator) : Businessman(mediator){}
​
    void sendMessage(const string& msg) override
    {
        m_pMediator->send(msg, this);
    }
​
    void getMessage(const string& msg)
    {
        cout << "Buyer recv: " << msg.data() << endl;
    }
};
​
//具体同事类
class Seller : public Businessman
{
public:
    Seller() : Businessman(){}
    Seller(Mediator* mediator) : Businessman(mediator){}
​
    void sendMessage(const string& msg) override
    {
        m_pMediator->send(msg, this);
    }
​
    void getMessage(const string& msg)
    {
        cout << "Seller recv: " << msg.data() << endl;
    }
};
​
//具体中介者类
class HouseMediator : public Mediator
{
public:
    void setBuyer(Businessman* buyer) override
    {
        m_pBuyer = buyer;
    }
​
    void setSeller(Businessman* seller) override
    {
        m_pSeller = seller;
    }
​
    void send(const string& msg, Businessman* man) override
    {
        if(man == m_pBuyer)
        {
            m_pSeller->getMessage(msg);
        }
        else if(man == m_pSeller)
        {
            m_pBuyer->getMessage(msg);
        }
    }
​
private:
    Businessman* m_pBuyer;
    Businessman* m_pSeller;
};
​
int main()
{
    HouseMediator* hMediator = new HouseMediator;
    Buyer* buyer = new Buyer(hMediator);
    Seller* seller = new Seller(hMediator);
​
    hMediator->setBuyer(buyer);
    hMediator->setSeller(seller);
​
    buyer->sendMessage("Sell not to sell?");
    seller->sendMessage("Of course selling!");
​
    delete buyer;
    buyer = nullptr;
​
    delete seller;
    seller = nullptr;
​
    delete hMediator;
    hMediator = nullptr;
​
​
    return 0;
}

3、备忘录(Memento)
备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原来保存的状态。

备忘录模式中需要定义的角色类:

Originator(发起人):负责创建一个备忘录Memento,用以记录当前时刻自身的内部状态,并可使用备忘录恢复内部状态。Originator可以根据需要决定Memento存储自己的哪些内部状态。

Memento(备忘录):负责存储Originator对象的内部状态,并可以防止Originator以外的其他对象访问备忘录。备忘录有两个接口:Caretaker只能看到备忘录的窄接口,他只能将备忘录传递给其他对象。Originator却可看到备忘录的宽接口,允许它访问返回到先前状态所需要的所有数据。

Caretaker(管理者):负责备忘录Memento,不能对Memento的内容进行访问或者操作。

/*
* 关键代码:Memento类、Originator类、Caretaker类;Originator类不与Memento类耦合,而是与Caretaker类耦合。
*/
​
include <iostream>
​
using namespace std;
​
//需要保存的信息
typedef struct
{
    int grade;
    string arm;
    string corps;
}GameValue;
​
//Memento类
class Memento
{
public:
    Memento(){}
    Memento(GameValue value):m_gameValue(value){}
    GameValue getValue()
    {
        return m_gameValue;
    }
private:
    GameValue m_gameValue;
};
​
//Originator类
class Game
{
public:
    Game(GameValue value):m_gameValue(value)
    {}
    void addGrade()  //等级增加
    {
        m_gameValue.grade++;
    }
    void replaceArm(string arm)  //更换武器
    {
        m_gameValue.arm = arm;
    }
    void replaceCorps(string corps)  //更换工会
    {
        m_gameValue.corps = corps;
    }
    Memento saveValue()    //保存当前信息
    {
        Memento memento(m_gameValue);
        return memento;
    }
    void load(Memento memento) //载入信息
    {
        m_gameValue = memento.getValue();
    }
    void showValue()
    {
        cout << "Grade: " << m_gameValue.grade << endl;
        cout << "Arm  : " << m_gameValue.arm.data() << endl;
        cout << "Corps: " << m_gameValue.corps.data() << endl;
    }
private:
    GameValue m_gameValue;
};
​
//Caretaker类
class Caretake
{
public:
    void save(Memento memento)  //保存信息
    {
        m_memento = memento;
    }
    Memento load()            //读已保存的信息
    {
        return m_memento;
    }
private:
    Memento m_memento;
};
​
int main()
{
    GameValue v1 = {0, "Ak", "3K"};
    Game game(v1);    //初始值
    game.addGrade();
    game.showValue();
    cout << "----------" << endl;
    Caretake care;
    care.save(game.saveValue());  //保存当前值
    game.addGrade();          //修改当前值
    game.replaceArm("M16");
    game.replaceCorps("123");
    game.showValue();
    cout << "----------" << endl;
    game.load(care.load());   //恢复初始值
    game.showValue();
    return 0;
}

4、策略(Strategy)
策略模式是指定义一系列的算法,把它们单独封装起来,并且使它们可以互相替换,使得算法可以独立于使用它的客户端而变化,也是说这些算法所完成的功能类型是一样的,对外接口也是一样的,只是不同的策略为引起环境角色环境角色表现出不同的行为。

相比于使用大量的if…else,使用策略模式可以降低复杂度,使得代码更容易维护。

缺点:可能需要定义大量的策略类,并且这些策略类都要提供给客户端。

[环境角色] 持有一个策略类的引用,最终给客户端调用。
4.1传统策略实现模式

/*
* 关键代码:实现同一个接口。
* 以下代码实例中,以游戏角色不同的攻击方式为不同的策略,游戏角色即为执行不同策略的环境角色。
*/
​
#include <iostream>
​
using namespace std;
​
//抽象策略类,提供一个接口
class Hurt
{
public:
    virtual void blood() = 0;
};
​
//具体的策略实现类,具体实现接口, Adc持续普通攻击
class AdcHurt : public Hurt
{
public:
    void blood() override
    {
        cout << "Adc hurt, Blood loss" << endl;
    }
};
​
//具体的策略实现类,具体实现接口, Apc技能攻击
class ApcHurt : public Hurt
{
public:
    void blood() override
    {
        cout << "Apc Hurt, Blood loss" << endl;
    }
};
​
//环境角色类, 游戏角色战士,传入一个策略类指针参数。
class Soldier
{
public:
    Soldier(Hurt* hurt):m_pHurt(hurt)
    {
    }
    //在不同的策略下,该游戏角色表现出不同的攻击
    void attack()
    {
        m_pHurt->blood();
    }
private:
    Hurt* m_pHurt;
};
​
//定义策略标签
typedef enum
{
    Hurt_Type_Adc,
    Hurt_Type_Apc,
    Hurt_Type_Num
}HurtType;
​
//环境角色类, 游戏角色法师,传入一个策略标签参数。
class Mage
{
public:
    Mage(HurtType type)
    {
        switch(type)
        {
        case Hurt_Type_Adc:
            m_pHurt = new AdcHurt();
            break;
        case Hurt_Type_Apc:
            m_pHurt = new ApcHurt();
            break;
        default:
            break;
        }
    }
    ~Mage()
    {
        delete m_pHurt;
        m_pHurt = nullptr;
        cout << "~Mage()" << endl;
    }
​
    void attack()
    {
        m_pHurt->blood();
    }
private:
    Hurt* m_pHurt;
};
​
//环境角色类, 游戏角色弓箭手,实现模板传递策略。
template<typename T>
class Archer
{
public:
    void attack()
    {
        m_hurt.blood();
    }
private:
    T m_hurt;
};
​
int main()
{
    Archer<ApcHurt>* arc = new Archer<ApcHurt>;
    arc->attack();
​
    delete arc;
    arc = nullptr;

    return 0;
}

4.2使用函数指针实现策略模式

#include <iostream>
#include <functional>
​
void adcHurt()
{
    std::cout << "Adc Hurt" << std::endl;
}
​
void apcHurt()
{
    std::cout << "Apc Hurt" << std::endl;
}
​
//环境角色类, 使用传统的函数指针
class Soldier
{
public:
    typedef void (*Function)();
    Soldier(Function fun): m_fun(fun)
    {
    }
    void attack()
    {
        m_fun();
    }
private:
    Function m_fun;
};
​
//环境角色类, 使用std::function<>
class Mage
{
public:
    typedef std::function<void()> Function;
​
    Mage(Function fun): m_fun(fun)
    {
    }
    void attack()
    {
        m_fun();
    }
private:
    Function m_fun;
};
​
int main()
{
    Soldier* soldier = new Soldier(apcHurt);
    soldier->attack();
    delete soldier;
    soldier = nullptr;
    return 0;
}

5、模板方法(Template Method)
模板模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

当多个类有相同的方法,并且逻辑相同,只是细节上有差异时,可以考虑使用模板模式。具体的实现上可以将相同的核心算法设计为模板方法,具体的实现细节有子类实现。

缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

以生产电脑为例,电脑生产的过程都是一样的,只是一些装配的器件可能不同而已。

/*
* 关键代码:在抽象类实现通用接口,细节变化在子类实现。
*/
​
#include <iostream>
​
using namespace std;
​
class Computer
{
public:
    void product()
    {
        installCpu();
        installRam();
        installGraphicsCard();
    }
​
protected:
    virtual void installCpu() = 0;
    virtual void installRam() = 0;
    virtual void installGraphicsCard() = 0;
​
};
​
class ComputerA : public Computer
{
protected:
    void installCpu() override
    {
        cout << "ComputerA install Inter Core i5" << endl;
    }
​
    void installRam() override
    {
        cout << "ComputerA install 2G Ram" << endl;
    }
​
    void installGraphicsCard() override
    {
        cout << "ComputerA install Gtx940 GraphicsCard" << endl;
    }
};
​
class ComputerB : public Computer
{
protected:
    void installCpu() override
    {
        cout << "ComputerB install Inter Core i7" << endl;
    }
​
    void installRam() override
    {
        cout << "ComputerB install 4G Ram" << endl;
    }
​
    void installGraphicsCard() override
    {
        cout << "ComputerB install Gtx960 GraphicsCard" << endl;
    }
};
​
int main()
{
    ComputerB* c1 = new ComputerB();
    c1->product();
​
    delete c1;
    c1 = nullptr;
​
    return 0;
}

6、访问者(Visitor)
7、观察者(Observer)
观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都要得到通知并自动更新。

观察者模式从根本上讲必须包含两个角色:观察者和被观察对象。

被观察对象自身应该包含一个容器来存放观察者对象,当被观察者自身发生改变时通知容器内所有的观察者对象自动更新。

观察者对象可以注册到被观察者的中,完成注册后可以检测被观察者的变化,接收被观察者的通知。当然观察者也可以被注销掉,停止对被观察者的监控。

/*
* 关键代码:在目标类中增加一个ArrayList来存放观察者们。
*/
#include <iostream>
#include <list>
#include <memory>
​
using namespace std;
​
class View;
​
//被观察者抽象类   数据模型
class DataModel
{
public:
    virtual ~DataModel(){}
    virtual void addView(View* view) = 0;
    virtual void removeView(View* view) = 0;
    virtual void notify() = 0;   //通知函数
};
​
//观察者抽象类   视图
class View
{
public:
    virtual ~View(){ cout << "~View()" << endl; }
    virtual void update() = 0;
    virtual void setViewName(const string& name) = 0;
    virtual const string& name() = 0;
};
​
//具体的被观察类, 整数模型
class IntDataModel:public DataModel
{
public:
    ~IntDataModel()
    {
        m_pViewList.clear();
    }
​
    virtual void addView(View* view) override
    {
        shared_ptr<View> temp(view);
        auto iter = find(m_pViewList.begin(), m_pViewList.end(), temp);
        if(iter == m_pViewList.end())
        {
            m_pViewList.push_front(temp);
        }
        else
        {
            cout << "View already exists" << endl;
        }
    }
​
    void removeView(View* view) override
    {
        auto iter = m_pViewList.begin();
        for(; iter != m_pViewList.end(); iter++)
        {
            if((*iter).get() == view)
            {
                m_pViewList.erase(iter);
                cout << "remove view" << endl;
                return;
            }
        }
    }
​
    virtual void notify() override
    {
        auto iter = m_pViewList.begin();
        for(; iter != m_pViewList.end(); iter++)
        {
            (*iter).get()->update();
        }
    }
​
private:
    list<shared_ptr<View>> m_pViewList;
};
​
//具体的观察者类    表视图
class TableView : public View
{
public:
    TableView() : m_name("unknow"){}
    TableView(const string& name) : m_name(name){}
    ~TableView(){ cout << "~TableView(): " << m_name.data() << endl; }
​
    void setViewName(const string& name)
    {
        m_name = name;
    }
​
    const string& name()
    {
        return m_name;
    }
​
    void update() override
    {
        cout << m_name.data() << " update" << endl;
    }
​
private:
    string m_name;
};
​
int main()
{
    /*
    * 这里需要补充说明的是在此示例代码中,View一旦被注册到DataModel类之后,DataModel解析时会自动解析掉     * 内部容器中存储的View对象,因此注册后的View对象不需要在手动去delete,再去delete View对象会出错。
    */

    View* v1 = new TableView("TableView1");
    View* v2 = new TableView("TableView2");
    View* v3 = new TableView("TableView3");
    View* v4 = new TableView("TableView4");
​
    IntDataModel* model = new IntDataModel;
    model->addView(v1);
    model->addView(v2);
    model->addView(v3);
    model->addView(v4);
​
    model->notify();
​
    cout << "-------------\n" << endl;
​
    model->removeView(v1);
​
    model->notify();
​
    delete model;
    model = nullptr;
​
    return 0;
}
​

参考文章
【1】https://www.cnblogs.com/chengjundu/p/8473564.html

标签:cout,--,void,模式,class,virtual,设计模式,public,Memento
来源: https://blog.csdn.net/weixin_43354152/article/details/112716314