4、行为型模式
约 7542 字大约 25 分钟
2025-06-22
也就是说对于某个员工的请求可能需要一级一级向上传递,如果有权处理那就将其处理掉,如果无权处理还需继续向上传递该请求。像上面这种将对象连成一条链,并沿着这条链传递请求,直到链上有一个对象将请求处理掉为止,这种处理数据的模式叫做责任链模式。使用这种模式有一个好处:处理者可以决定不再沿着链传递请求, 这可高效地取消所有后续处理步骤。 责任链会将特定行为转换为被称作处理者的独立对象。 在巴洛克工作社这个例子中, 每个审批步骤都可被抽取为仅有单个方法的类, 并执行审批操作,请求及其数据则会被作为参数传递给该方法。
enum class RequestType:char {QingJia, ZhangXin, CiZhi};
// 抽象的任务节点类
class AbstractManager
{
public:
void setNext(AbstractManager* manager)
{
m_next = manager;
}
virtual void handleRequest(RequestType type) = 0;
virtual ~AbstractManager() {}
protected:
AbstractManager* m_next = nullptr;
};
// 初级管理者
class Manager : public AbstractManager
{
public:
void handleRequest(RequestType type)
{
switch (type)
{
case RequestType::QingJia:
cout << "请假: 同意请假,好好休息~~~" << endl;
break;
case RequestType::ZhangXin:
cout << "涨薪: 这个我得请示一下咱们CEO..." << " ====> ";
m_next->handleRequest(type);
break;
case RequestType::CiZhi:
cout << "辞职: 我给你向上级反应一下..." << " ====> ";
m_next->handleRequest(type);
break;
default:
break;
}
}
};
// CEO
class CEO : public AbstractManager
{
public:
void handleRequest(RequestType type)
{
switch (type)
{
case RequestType::QingJia:
cout << "请假: 同意请假, 下不为例..." << endl;
break;
case RequestType::ZhangXin:
cout << "涨薪: 你工资不少了, 给你个购物券吧..." << endl;
break;
case RequestType::CiZhi:
cout << "辞职: 这个我得问问咱们老板..." << " ====> ";
m_next->handleRequest(type);
break;
default:
break;
}
}
};
// 老板
class Boss : public AbstractManager
{
public:
void handleRequest(RequestType type)
{
switch (type)
{
case RequestType::QingJia:
cout << "请假: 只有工作才能实现人生价值,回去好好坚守岗位!!!" << endl;
break;
case RequestType::ZhangXin:
cout << "涨薪: 钱财乃身外之物, 要视其如粪土!!!" << endl;
break;
case RequestType::CiZhi:
cout << "辞职: 巴洛克工作社就是你的家, 这次把你留下, 下次别再提了!!!" << endl;
break;
default:
break;
}
}
};
// 卑微的大聪明
class DaCongMing
{
public:
void request(RequestType type, AbstractManager* manager)
{
manager->handleRequest(type);
}
};
int main()
{
Manager* manager = new Manager;
CEO* ceo = new CEO;
Boss* boss = new Boss;
// 设置关联关系
manager->setNext(ceo);
ceo->setNext(boss);
// 卑微的大聪明的请求
DaCongMing* boy = new DaCongMing;
cout << "========== 大聪明向顶头上司提要求 ==========" << endl;
boy->request(RequestType::QingJia, manager);
boy->request(RequestType::ZhangXin, manager);
boy->request(RequestType::CiZhi, manager);
cout << "========== 大聪明越级找CEO提要求 ==========" << endl;
boy->request(RequestType::QingJia, ceo);
boy->request(RequestType::ZhangXin, ceo);
boy->request(RequestType::CiZhi, ceo);
cout << "========== 大聪明直接找BOSS提要求 ==========" << endl;
boy->request(RequestType::QingJia, boss);
boy->request(RequestType::ZhangXin, boss);
boy->request(RequestType::CiZhi, boss);
delete boy;
delete manager;
delete ceo;
delete boss;
return 0;
}
责任链模式就是将这些处理者连成一条链。 链上的每个处理者都有一个成员变量来保存下一个处理者。 除了处理请求外, 处理者还负责沿着链传递请求, 请求会在链上移动, 直至所有处理者都有机会对其进行处理。
命令模式
我们可以将顾客的点餐列表看作是一个待执行的命令的列表,这样就可以总结出三者之间的关系了:厨师哲普是这些命令的接收者和执行者,路飞是这些命令的调用者。如果没有这张点餐列表,路飞需要非常频繁地穿梭在餐厅与厨房之间,而且哪个顾客点了什么菜也容易弄混,从某种程度上讲这个点餐列表就相当于一个任务队列。
上面的这种解决问题的思路用到的就是设计模式中的命令模式。命令模式就是将请求转换为一个包含与请求相关的所有信息的独立对象,通过这个转换能够让使用者根据不同的请求将客户参数化、 延迟请求执行或将请求放入队列中或记录请求日志, 且能实现可撤销操作。
#include <iostream>
#include <map>
using namespace std;
// 命令模式
// 厨师
class Cook {
public:
void makeDXY() { cout << "炼定仙游蛊" << endl; }
void makeHYQT() { cout << "炼鸿运齐天蛊" << endl; }
};
// 命令抽象类
class AbstractCommand {
protected:
Cook* cook;
public:
AbstractCommand(Cook* cook) : cook(cook) {}
virtual ~AbstractCommand() {}
virtual string execute() = 0;
};
// 炼定仙游蛊命令
class DXYCommand : public AbstractCommand {
public:
using AbstractCommand::AbstractCommand;
string execute() override {
cook->makeDXY();
return "定仙游蛊";
}
};
// 炼鸿运齐天蛊命令
class HYQTCommand : public AbstractCommand {
public:
using AbstractCommand::AbstractCommand;
string execute() override {
cook->makeHYQT();
return "鸿运齐天蛊";
}
};
// 服务员
class Waiter {
private:
map<int, AbstractCommand*> commands;
public:
void order(int id, AbstractCommand* command) {
cout << id << "号下单" << command->execute() << endl;
commands.insert(pair<int, AbstractCommand*>(id, command));
}
};
void test() {
Cook* cook = new Cook();
Waiter* waiter = new Waiter();
waiter->order(1, new DXYCommand(cook));
waiter->order(2, new HYQTCommand(cook));
waiter->order(3, new DXYCommand(cook));
}
这个厨师类是命令模式中命令的接收者,收不到命令厨师是不能工作的。 顾客下单就是命令模式中的命令,这些命令的接收者是厨师,命令被分离出来实现了和厨师类的解耦合。通过这种方式可以控制命令执行的时机,毕竟厨师都是在顾客点餐完毕之后才开始炒菜的。 在命令模式中,服务员类是命令的调用者,顾客点餐完成之后服务员调用这些命令,命令的接收者也是执行者 – 厨师就开始给顾客做菜了。
命令模式最大的特点就是松耦合设计,它有以下几个优势:
- 使用这种模式可以很容易地设计出一个命令队列(对应路飞类中的点餐列表)
- 可以很容易的将命令记录到日志中(对应例子中的账单信息)
- 允许接收请求的一方决定是否要否决请求(对应例子中的鱼香肉丝)
- 可以很容易的实现对请求的撤销和重做(对应例子中的撤单函数)
迭代器模式
如果按照人员的等级划分来存储这些团员信息,遍历他们有两种方式:深度优先搜索和广度优先搜索;如果存储海贼团成员信息的时候使用的是线性表或者其他结构,现有的遍历算法可能就不再适用了,最优的解决方案就是将集合与它对应的遍历算法解耦。
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 需要提供一种解决方案使其能够顺序访问一个集合对象中的各个元素,而又不暴露该集合底层的表现形式(列表、栈、树、图等),这种行为设计模式就叫迭代器模式。
#pragma once
#include <string>
using namespace std;
// 定义一个链表节点
struct Node
{
Node(string n) : name(n) {}
string name = string();
Node* next = nullptr;
Node* prev = nullptr;
};
// 双向链表
class MyList
{
public:
inline int getCount()
{
return m_count;
}
inline Node* head()
{
return m_head;
}
inline Node* tail()
{
return m_tail;
}
Node* insert(Node* item, string data);
Node* pushFront(string data);
Node* pushBack(string data);
private:
Node* m_head = nullptr;
Node* m_tail = nullptr;
int m_count = 0;
};
#include "MyList.h"
Node* MyList::insert(Node* item, string data)
{
Node* node = nullptr;
if (item == m_head)
{
node = pushFront(data);
}
else
{
node = new Node(data);
node->next = item;
node->prev = item->prev;
// 重新连接
item->prev->next = node;
item->prev = node;
m_count++;
}
m_count++;
return node;
}
Node* MyList::pushFront(string data)
{
Node* node = new Node(data);
// 空链表
if (m_head == nullptr)
{
m_head = m_tail = node;
}
else
{
node->next = m_head;
m_head->prev = node;
m_head = node;
}
m_count++;
return node;
}
Node* MyList::pushBack(string data)
{
Node* node = new Node(data);
// 空链表
if (m_tail == nullptr)
{
m_head = m_tail = node;
}
else
{
m_tail->next = node;
node->prev = m_tail;
m_tail = node;
}
m_count++;
return node;
}
如果想要遍历上面的链表集合,有两种方式:一种是正向遍历,一种是逆向遍历,不论哪一种遍历方式它们都对应相同的操作接口,所以需要先提供一个抽象的迭代器基类。通过代器接口访问上面的双向链表的时候,我们只知道它是一个容器,至于其内部的数据结构已经全部被隐藏了。
// 抽象的迭代器类
class Iterator
{
public:
Iterator(MyList* mylist) : m_list(mylist) {}
Node* current()
{
return m_current;
}
virtual Node* first() = 0;
virtual Node* next() = 0;
virtual bool isDone() = 0;
virtual ~Iterator() {}
protected:
MyList* m_list = nullptr;
Node* m_current = nullptr;
};
在这个迭代器基类的内部包含一个双向链表的实例对象 m_list,通过迭代器类遍历双向链表的时候: 通过isDone()函数判断遍历是否结束了 通过current()函数得到遍历到的当前节点 在进行正向遍历的时候: 通过first()函数得到链表的头结点 通过next()函数得到当前节点的后继节点 在进行逆向遍历的时候: 通过first()函数得到链表的尾结点 通过next()函数得到当前节点的前驱节点
// 正向迭代器
class ForwardIterator : public Iterator
{
public:
using Iterator::Iterator;
Node* first() override
{
m_current = m_list->head();
return m_current;
}
Node* next() override
{
m_current = m_current->next;
return m_current;
}
bool isDone() override
{
return m_current == m_list->tail()->next;
}
};
// 逆向迭代器
class ReverseIterator : public Iterator
{
public:
using Iterator::Iterator;
Node* first() override
{
m_current = m_list->tail();
return m_current;
}
Node* next() override
{
m_current = m_current->prev;
return m_current;
}
bool isDone() override
{
return m_current == m_list->head()->prev;
}
};
在子类ForwardIterator 和ReverseIterator 中分别重写父类的纯虚函数,实现了对双向链表的正向遍历和逆向遍历。通过编写的代码我们可以非常清晰的看到,其实所谓的迭代器模式就是专门针对某个容器的遍历提供对应的操作类,通过迭代器类的封装使对应的容器的遍历操作变得简单,并且隐藏了容器的内部细节。
#pragma once
#include <string>
using namespace std;
// 定义一个链表节点
struct Node
{
Node(string n) : name(n) {}
string name = string();
Node* next = nullptr;
Node* prev = nullptr;
};
class Iterator;
// 双向链表
class MyList
{
public:
inline int getCount()
{
return m_count;
}
inline Node* head()
{
return m_head;
}
inline Node* tail()
{
return m_tail;
}
Node* insert(Node* item, string data);
Node* pushFront(string data);
Node* pushBack(string data);
Iterator* getIterator(bool isReverse = false);
private:
Node* m_head = nullptr;
Node* m_tail = nullptr;
int m_count = 0;
};
#include "MyList.h"
#include "Iterator.h"
Node* MyList::insert(Node* item, string data)
{
Node* node = nullptr;
if (item == m_head)
{
node = pushFront(data);
}
else
{
node = new Node(data);
node->next = item;
node->prev = item->prev;
// 重新连接
item->prev->next = node;
item->prev = node;
m_count++;
}
return node;
}
Node* MyList::pushFront(string data)
{
Node* node = new Node(data);
// 空链表
if (m_head == nullptr)
{
m_head = m_tail = node;
}
else
{
node->next = m_head;
m_head->prev = node;
m_head = node;
}
m_count++;
return node;
}
Node* MyList::pushBack(string data)
{
Node* node = new Node(data);
// 空链表
if (m_tail == nullptr)
{
m_head = m_tail = node;
}
else
{
m_tail->next = node;
node->prev = m_tail;
m_tail = node;
}
m_count++;
return node;
}
Iterator* MyList::getIterator(bool isReverse)
{
Iterator* iterator = nullptr;
if (isReverse)
{
iterator = new ReverseIterator(this);
}
else
{
iterator = new ForwardIterator(this);
}
return iterator;
}
int main()
{
vector<string> nameList{
"烬", "奎因", "杰克", "福兹·弗", "X·德雷克",
"黑色玛利亚", "笹木", "润媞", "佩吉万",
"一美", "二牙", "三鬼", "四鬼", "五鬼",
"六鬼", "七鬼", "八茶", "九忍","十鬼"
};
MyList mylist;
for (int i = 0; i < nameList.size(); ++i)
{
mylist.pushBack(nameList.at(i));
}
// 遍历
Iterator* it = mylist.getIterator(true);
cout << "检阅开始, 凯多: 同志们辛苦啦~~~~~" << endl;
for (auto begin = it->first(); !it->isDone(); it->next())
{
cout << " " << it->current()->name << "say: 为老大服务!!! " << endl;
}
cout << endl;
delete it;
return 0;
}
迭代器模式是一个很经典的模式。所以没必要重复的去造这个轮子,成型的类库都非常好的实现了迭代器模式,在使用这些类库提供的容器时,并不需要我们亲自去实现对应的迭代器,比如 STL。但是,打铁还需自身硬,对于这些必备技能我们是没有理由不去学习和掌握的。
中介者模式
中介者模式可以减少对象之间混乱无序的依赖关系,从而使其耦合松散,限制对象之间的直接交互,迫使它们通过一个中介者对象进行合作。
如果不使用中介者模式,各个国家之间的关系就是一个网状结构,关系错综复杂,这样的系统也很难容易维护。有了中介者对象,可以将系统的网状结构变成以中介者为中心的放射形结构。每个具体的对象不再通过直接的联系与另一对象发生相互作用,而是通过中介者对象与另一个对象发生相互作用。
// 抽象国家类
class Country
{
public:
Country(){}
// 发表声明
virtual void declare(string msg, string country) = 0;
virtual void setMessage(string msg) = 0;
virtual string getName() = 0;
};
// 抽象的中介机构
class MediatorOrg
{
public:
void addMember(Country* country);
virtual void declare(string msg, Country* country, string name = string()) = 0;
virtual ~MediatorOrg() {}
protected:
map<string, Country*> m_countryMap;
};
// 世界政府
class Country;
class WorldGovt : public MediatorOrg
{
public:
void declare(string msg, Country* country, string name = string()) override;
};
#include <iostream>
#include "Mediator.h"
#include "Country.h"
using namespace std;
// 基类的成员添加函数
void MediatorOrg::addMember(Country* country)
{
m_countryMap.insert(make_pair(country->getName(), country));
}
// 在子类中重写发表声明的函数
void WorldGovt::declare(string msg, Country* country, string name)
{
if (m_countryMap.find(name) != m_countryMap.end())
{
string str = msg + "【来自: " + country->getName() + "】";
m_countryMap[name]->setMessage(str);
}
}
// 革命军
class GeMingArmy : public MediatorOrg
{
public:
void declare(string msg, Country* country, string name = string()) override;
};
// 在子类中重写发表声明的函数
void GeMingArmy::declare(string msg, Country* country, string name)
{
string str = msg + "【来自: " + country->getName() + "】";
for (const auto& item : m_countryMap)
{
if (item.second == country)
{
continue;
}
item.second->setMessage(str);
}
}
// 抽象国家类
class Country
{
public:
Country(MediatorOrg* mediator) : m_mediator(mediator) {}
// 发表声明
virtual void declare(string msg, string country) = 0;
virtual void setMessage(string msg) = 0;
virtual string getName() = 0;
virtual ~Country() {}
protected:
MediatorOrg* m_mediator = nullptr;
};
#pragma once
#include <string>
#include <iostream>
#include "Mediator.h"
using namespace std;
// 抽象国家类
class Country
{
public:
Country(MediatorOrg* mediator) : m_mediator(mediator) {}
// 发表声明
virtual void declare(string msg, string country) = 0;
virtual void setMessage(string msg) = 0;
virtual string getName() = 0;
virtual ~Country() {}
protected:
MediatorOrg* m_mediator = nullptr;
};
// 阿拉巴斯坦
class Alabasta : public Country
{
public:
using Country::Country;
void declare(string msg, string country) override
{
m_mediator->declare(msg, this, country);
}
void setMessage(string msg) override
{
cout << "阿拉巴斯坦得到的消息: " << msg << endl;
}
string getName() override
{
return "阿拉巴斯坦";
}
};
// 德雷斯罗萨
class Dressrosa : public Country
{
public:
using Country::Country;
void declare(string msg, string country) override
{
m_mediator->declare(msg, this, country);
}
void setMessage(string msg) override
{
cout << "德雷斯罗萨得到的消息: " << msg << endl;
}
string getName() override
{
return "德雷斯罗萨";
}
};
// 露露西亚王国
class Lulusia : public Country
{
public:
using Country::Country;
void declare(string msg, string country) override
{
m_mediator->declare(msg, this, country);
}
void setMessage(string msg) override
{
cout << "露露西亚得到的消息: " << msg << endl;
}
string getName() override
{
return "露露西亚";
}
};
// 卡玛巴卡王国
class Kamabaka : public Country
{
public:
using Country::Country;
void declare(string msg, string country) override
{
m_mediator->declare(msg, this, country);
}
void setMessage(string msg) override
{
cout << "卡玛巴卡得到的消息: " << msg << endl;
}
string getName() override
{
return "卡玛巴卡";
}
};
int main()
{
// 世界政府
WorldGovt* world = new WorldGovt;
Alabasta* alaba = new Alabasta(world);
Dressrosa* dresa = new Dressrosa(world);
// 世界政府添加成员
world->addMember(alaba);
world->addMember(dresa);
// 世界政府成员发声
alaba->declare("德雷斯罗萨倒卖军火, 搞得我国连年打仗, 必须给个说法!!!", dresa->getName());
dresa->declare("天龙人都和我多弗朗明哥做生意, 你算老几, 呸!!!", alaba->getName());
cout << "======================================" << endl;
// 革命军
GeMingArmy* geming = new GeMingArmy;
Lulusia* lulu = new Lulusia(geming);
Kamabaka* kama = new Kamabaka(geming);
geming->addMember(lulu);
geming->addMember(kama);
lulu->declare("我草, 我的国家被伊姆毁灭了!!!", lulu->getName());
delete world;
delete alaba;
delete dresa;
delete geming;
delete lulu;
delete kama;
return 0;
}
当一些对象和其他对象紧密耦合以致难以对其进行修改时;当组件因过于依赖其他组件而无法在不同应用中复用时;当为了能在不同情景下复用一些基本行为,导致需要被迫创建大量组件子类时,都可使用中介者模式。
备忘录模式
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后在需要的时候就可以将该对象恢复到原先保存的状态。
历史的进程有一定的脉络,作为程序猿的我们可以把历史拆分为这么几个部分:
- 历史中的亲历者(个人或群体)
- 历史中发生的事情的来龙去脉
- 记录历史的人 这三部分数据也是备忘录模式中的三要素:事件的主体、事件的内容、事件的记录者。在事件主体上发生的事情就是事件的内容,事件的内容通过事件记录者进行备份。很显然,在备忘录模式中将事件的主体和事件的内容进行解耦合更有利于程序的扩展和维护。根据上面的描述,我们就可以把这三者之间的对应关系通过UML类图描述出来了:
#include <iostream>
#include <map>
using namespace std;
// 备忘录模式
// 历史备忘录类
class History {
private:
string msg;
public:
History(string msg) : msg(msg) {}
string getMsg() { return msg; }
};
// 事件亲历者
class Person {
public:
History* saveHistory(string msg) { return new History(msg); }
void showHistory(History* history) {
cout << "历史事件:" << history->getMsg() << endl;
}
};
// 记录者
class Recorder {
private:
map<int, History*> historyMap;
public:
void addHistory(int id, History* history) {
historyMap.insert(pair<int, History*>(id, history));
}
History* getHistory(int id) { return historyMap[id]; }
};
void test(){
Person person;
Recorder recorder;
for (int i = 0; i < 5; i++) {
History* history = person.saveHistory("事件" + to_string(i));
recorder.addHistory(i, history);
}
for (int i = 0; i < 5; i++) {
History* history = recorder.getHistory(i);
person.showHistory(history);
}
}
观察者模式
观察者模式允许我们定义一种订阅机制,可在对象事件发生时通知所有的观察者对象,使它们能够自动更新。观察者模式还有另外一个名字叫做“发布-订阅”模式。
#include <iostream>
#include <list>
using namespace std;
// 观察者模式
class Subject;
// 抽象观察者
class Observer {
protected:
list<Subject*> subjects;
public:
// 添加订阅者
void addSubject(Subject* subject){
subjects.emplace_back(subject);
}
// 取消订阅者
void removeSubject(Subject* subject){
subjects.remove(subject);
}
// 通知订阅者
virtual void update(string msg) = 0;
virtual ~Observer() = default;
};
// 订阅者
class Subject {
public:
Subject(Observer* observer){
observer->addSubject(this);
}
virtual void revMsg(string msg)=0;
};
// 新闻社
class NewsAgency : public Observer {
public:
void update(string msg) override {
cout << "新闻社有" << subjects.size() << "人订阅" << endl;
for (const auto& subject : subjects) {
subject->revMsg(msg);
}
}
};
// 订阅者
class Subscriber : public Subject {
using Subject::Subject;
void revMsg(string msg) override {
cout << "订阅者收到消息:" << msg << endl;
}
};
void test(){
NewsAgency newsAgency;
Subscriber subscriber1(&newsAgency);
Subscriber subscriber2(&newsAgency);
Subscriber subscriber3(&newsAgency);
newsAgency.update("新闻1");
newsAgency.update("新闻2");
}
当一个对象的状态发生变化,并且需要改变其它对象的时候;或者当应用中一些对象必须观察其它对象的时候可以使用观察者模式。
策略模式
策略模式需要我们定义一系列的算法,并且将每种算法都放入到独立的类中,在实际操作的时候使这些算法对象可以相互替换。 把处理逻辑分散到多个不同的策略类中,这样就可以将复杂的逻辑简化了。
// 抽象的策略类
class AbstractStrategy
{
public:
virtual void fight(bool isfar = false) = 0;
virtual ~AbstractStrategy() {}
};
// 一档
class YiDang : public AbstractStrategy
{
public:
void fight(bool isfar = false) override
{
cout << "*** 现在使用的是一档: ";
if (isfar)
{
cout << "橡胶机关枪" << endl;
}
else
{
cout << "橡胶·攻城炮" <<endl;
}
}
};
// 二挡
class ErDang : public AbstractStrategy
{
public:
void fight(bool isfar = false) override
{
cout << "*** 切换成二挡: ";
if (isfar)
{
cout << "橡胶Jet火箭" << endl;
}
else
{
cout << "橡胶Jet·铳乱打" << endl;
}
}
};
// 三挡
class SanDang : public AbstractStrategy
{
public:
void fight(bool isfar = false) override
{
cout << "*** 切换成三挡: ";
if (isfar)
{
cout << "橡胶巨人回旋弹" << endl;
}
else
{
cout << "橡胶巨人战斧" << endl;
}
}
};
// 四挡
class SiDang : public AbstractStrategy
{
public:
void fight(bool isfar = false) override
{
cout << "*** 切换成四挡: ";
if (isfar)
{
cout << "橡胶狮子火箭炮" << endl;
}
else
{
cout << "橡胶犀牛榴弹炮" << endl;
}
}
};
// 五档
class WuDang : public AbstractStrategy
{
public:
void fight(bool isfar = false) override
{
cout << "*** 切换成五挡: 变成尼卡形态可以把物体变成橡胶, 并任意改变物体的形态对其进行攻击!!!" << endl;
}
};
// 难度级别
enum class Level:char {Easy, Normal, Hard, Experts, Professional};
// 路飞
class Luffy
{
public:
void fight(Level level, bool isfar = false)
{
if (m_strategy)
{
delete m_strategy;
m_strategy = nullptr;
}
switch (level)
{
case Level::Easy:
m_strategy = new YiDang;
break;
case Level::Normal:
m_strategy = new ErDang;
break;
case Level::Hard:
m_strategy = new SanDang;
break;
case Level::Experts:
m_strategy = new SiDang;
break;
case Level::Professional:
m_strategy = new WuDang;
break;
default:
break;
}
m_strategy->fight(isfar);
}
~Luffy()
{
delete m_strategy;
}
private:
AbstractStrategy* m_strategy = nullptr;
};
int main()
{
Luffy* luffy = new Luffy;
cout << "--- 在香波地群岛遇到了海军士兵: " << endl;
luffy->fight(Level::Easy);
cout << "--- 在魔谷镇遇到了贝拉米: " << endl;
luffy->fight(Level::Normal);
cout << "--- 在司法岛遇到了罗布·路奇: " << endl;
luffy->fight(Level::Hard);
cout << "--- 在德雷斯罗萨遇到了多弗朗明哥: " << endl;
luffy->fight(Level::Experts);
cout << "--- 在鬼岛遇到了凯多: " << endl;
luffy->fight(Level::Professional);
delete luffy;
return 0;
}
策略模式中的若干个策略对象相互之间是完全独立的, 它们不知道其他对象的存在。当我们想使用对象中各种不同的算法变体,并希望能够在运行的时候切换这些算法时,可以选择使用策略模式来处理这个问题。
状态模式
状态模式就是在一个类的内部会有多种状态的变化,因为状态变化从而导致其行为的改变,在类的外部看上去这个类就像是自身发生了改变一样。 状态模式和策略模式比较类似,策略模式中的各个策略是独立的不关联的,但是状态模式下的对象的各种状态可以是独立的也可以是相互依赖的
// State.h
// 抽象状态
class Sanji;
class AbstractState
{
public:
virtual void working(Sanji* sanji) = 0;
virtual ~AbstractState() {}
};
// 上午状态
class ForenoonState : public AbstractState
{
public:
void working(Sanji* sanji) override;
};
// 中午状态
class NoonState : public AbstractState
{
public:
void working(Sanji* sanji) override;
};
// 下午状态
class AfternoonState : public AbstractState
{
public:
void working(Sanji* sanji) override;
};
// 晚上状态
class EveningState : public AbstractState
{
public:
void working(Sanji* sanji) override;
};
#include <iostream>
#include "State.h"
#include "Sanji.h"
using namespace std;
void ForenoonState::working(Sanji* sanji)
{
int time = sanji->getClock();
if (time < 8)
{
cout << "当前时间<" << time << ">点, 准备早餐, 布鲁克得多喝点牛奶..." << endl;
}
else if (time > 8 && time < 11)
{
cout << "当前时间<" << time << ">点, 去船头钓鱼, 储备食材..." << endl;
}
else
{
sanji->setState(new NoonState);
sanji->working();
}
}
void NoonState::working(Sanji* sanji)
{
int time = sanji->getClock();
if (time < 13)
{
cout << "当前时间<" << time << ">点, 去厨房做午饭, 给路飞多做点肉..." << endl;
}
else
{
sanji->setState(new AfternoonState);
sanji->working();
}
}
void AfternoonState::working(Sanji* sanji)
{
int time = sanji->getClock();
if (time < 15)
{
cout << "当前时间<" << time << ">点, 准备下午茶, 给罗宾和娜美制作爱心甜点..." << endl;
}
else if (time > 15 && time < 18)
{
cout << "当前时间<" << time << ">点, 和乔巴去船尾钓鱼, 储备食材..." << endl;
}
else
{
sanji->setState(new EveningState);
sanji->working();
}
}
void EveningState::working(Sanji* sanji)
{
int time = sanji->getClock();
if (time < 19)
{
cout << "当前时间<" << time << ">点, 去厨房做晚饭, 让索隆多喝点汤..." << endl;
}
else
{
cout << "当前时间<" << time << ">点, 今天过得很高兴, 累了睡觉了..." << endl;
}
}
状态模式下各个模式之间是可以有依赖关系的,这一点和策略模式是有区别的,策略模式下各个策略都是独立的,当前策略不知道有其它策略的存在。
// Sanji.h
#pragma once
#include "State.h"
class Sanji
{
public:
Sanji()
{
m_state = new ForenoonState;
}
void working()
{
m_state->working(this);
}
void setState(AbstractState* state)
{
if (m_state != nullptr)
{
delete m_state;
}
m_state = state;
}
void setClock(int time)
{
m_clock = time;
}
int getClock()
{
return m_clock;
}
~Sanji()
{
delete m_state;
}
private:
int m_clock = 0; // 时钟
AbstractState* m_state = nullptr;
};
int main()
{
Sanji* sanji = new Sanji;
// 时间点
vector<int> data{7, 10, 12, 14, 16, 18, 22};
for (const auto& item : data)
{
sanji->setClock(item);
sanji->working();
}
delete sanji;
return 0;
}
如果对象需要根据当前自身状态进行不同的行为, 同时状态的数量非常多且与状态相关的代码会频繁变更或者类对象在改变自身行为时需要使用大量的条件语句时,可使用状态模式。
模板方法模式
模板方法模式就是在基类中定义一个算法的框架,允许子类在不修改结构的情况下重写算法的特定步骤。说的再直白一些就是先定义一个基类,在基类中把与需求相关的所有操作函数全部作为虚函数定义出来,然后在这个基类的各个子类中重写父类的虚函数,这样子类基于父类的架构使自己有了和其他兄弟类不一样的行为。 模板方法这种设计模式是对多态的典型应用。
// 抽象机器人类
class AbstractRobot
{
public:
// 武器
virtual void weapon() = 0;
// 外观
virtual void appearance() = 0;
// 战斗能力
virtual void fightAbility() = 0;
// 名字
virtual string getName() = 0;
// 自愈能力
virtual void selfHealing() {};
// 是否能飞
virtual bool canFlying()
{
return false;
}
// 是否是自动控制
virtual bool isAuto()
{
return true;
}
// 得到机器人属性
virtual void getProperty()
{
cout << "贝加庞克制造的" << getName() << "有以下属性: " << endl;
if (canFlying())
{
cout << "有飞行能力!" << endl;
}
else
{
cout << "没有飞行能力!" << endl;
}
if (isAuto())
{
cout << "可以自动控制, 完全体机器人!" << endl;
}
else
{
cout << "不能自动控制, 半自动机器人!" << endl;
}
weapon();
appearance();
fightAbility();
selfHealing();
}
};
// 和平主义者
class Pacifist : public AbstractRobot
{
public:
// 武器
void weapon() override
{
cout << "可以发射镭射光..." << endl;
}
// 外观
void appearance() override
{
cout << "外部和巴索罗米·熊一样, 体型庞大,拥有呈半圆形的耳朵,内部似乎金属。" << endl;
}
// 能力
void fightAbility() override
{
cout << "结实抗揍, 可以通过手部或者嘴部发射镭射激光, 可以融化钢铁!!!" << endl;
}
string getName() override
{
return "和平主义者";
}
};
// 炽天使
class Seraphim : public AbstractRobot
{
public:
// 武器
void weapon() override
{
cout << "可以发射镭射激光, 鹰眼外形的炽天使携带者一把巨剑, 可以斩断一切!!!" << endl;
}
// 外观
void appearance() override
{
cout << "外观和七武海小时候的外形一样, 并且拥有一对和烬一样的翅膀!!!" << endl;
}
// 能力
void fightAbility() override
{
cout << "不仅可以发射镭射激光, 还拥有七武海的能力, 牛逼plus, 无敌了!!!!" << endl;
}
// 自愈能力
void selfHealing() override
{
cout << "非常厚实抗揍, 并且拥有非常强的自愈能力, 开挂了!!!" << endl;
}
// 是否能飞
bool canFlying() override
{
return true;
}
string getName() override
{
return "炽天使";
}
};
int main()
{
AbstractRobot* robot = nullptr;
robot = new Pacifist;
robot->getProperty();
delete robot;
cout << "====================================" << endl;
robot = new Seraphim;
robot->getProperty();
delete robot;
return 0;
}
我们在实现子类的时候,如果发现不变的行为和可变的行为混合在了一起,导致不变的行为在多个子类中重复出现,此时就可以使用模板方法模式把不变的行为搬到基类中,去除子类里边的重复代码,来体现它的优势,模板方法模式就是提供了一个很好的代码复用平台。
访问者模式
草帽团面对大熊的突如其来的攻击就两个状态:愤怒和恐惧,在这两种状态下的反应就是战斗和求助。所以我们可以把上面的这个场景重构一下:
如果草帽团的某些成员在面对大熊攻击时的状态反应是一样的,那么在这些子类中就会出现很多相同的冗余代码。有一种更好的处理思路就是将状态和人分开,其中草帽团的各个成员我们可以看做是对象,草帽团成员的反应和状态我们可以将其看做是算法,这种将算法与其所作用的对象隔离开来的设计模式就叫做访问者模式,其实就是通过被分离出的算法来访问对应的对象。
// 抽象的成员类
class AbstractMember
{
public:
AbstractMember(string name) : m_name(name){}
string getName()
{
return m_name;
}
// 接受状态对象的访问
virtual void accept(行为/动作类* action) = 0;
virtual ~AbstractMember() {}
protected:
string m_name;
};
// 男性成员
class MaleMember : public AbstractMember
{
public:
AbstractMember::AbstractMember;
void accept(行为/动作* action) override
{
// do something
}
};
// 女性成员
class FemaleMember : public AbstractMember
{
public:
AbstractMember::AbstractMember;
void accept(行为/动作* action) override
{
// do something
}
};
// 类声明
class MaleMember;
class FemaleMember;
// 抽象的动作类
class AbstractAction
{
public:
// 访问男人
virtual void maleDoing(MaleMember* male) = 0;
// 访问女人
virtual void femalDoing(FemaleMember* female) = 0;
virtual ~AbstractAction() {}
};
// 愤怒
class Anger : public AbstractAction
{
public:
void maleDoing(MaleMember* male) override;
void femalDoing(FemaleMember* female) override;
void warning();
void fight();
};
// 恐惧
class Horror : public AbstractAction
{
public:
void maleDoing(MaleMember* male) override;
void femalDoing(FemaleMember* female) override;
void help();
void thinking();
};
#include <iostream>
#include "Visitor.h"
#include "Member.h"
#include <list>
#include <vector>
using namespace std;
void Anger::maleDoing(MaleMember* male)
{
cout << "我是草帽海贼团的" << male->getName() << endl;
fight();
}
void Anger::femalDoing(FemaleMember* female)
{
cout << "我是草帽海贼团的" << female->getName() << endl;
warning();
}
void Anger::warning()
{
cout << "大家块逃,我快顶不住了, 不要管我!!!" << endl;
}
void Anger::fight()
{
cout << "只要还活着就得跟这家伙血战到底!!!" << endl;
}
void Horror::maleDoing(MaleMember* male)
{
cout << "我是草帽海贼团的" << male->getName() << endl;
thinking();
}
void Horror::femalDoing(FemaleMember* female)
{
cout << "我是草帽海贼团的" << female->getName() << endl;
help();
}
void Horror::help()
{
cout << "这个大熊太厉害, 太可怕了, 快救救我。。。" << endl;
}
void Horror::thinking()
{
cout << "得辅助同伴们一块攻击这个家伙, 不然根本打不过呀!!!" << endl;
}
// Visitor.cpp
// 草帽团
class CaoMaoTeam
{
public:
CaoMaoTeam()
{
m_actions.push_back(new Anger);
m_actions.push_back(new Horror);
}
void add(AbstractMember* member)
{
m_members.push_back(member);
}
void remove(AbstractMember* member)
{
m_members.remove(member);
}
void display()
{
for (const auto& item : m_members)
{
int index = rand() % 2;
item->accept(m_actions[index]);
}
}
~CaoMaoTeam()
{
for (const auto& item : m_members)
{
delete item;
}
for (const auto& item : m_actions)
{
delete item;
}
}
private:
list<AbstractMember*> m_members;
vector<AbstractAction*> m_actions;
};
#pragma once
#include <iostream>
#include "Visitor.h"
using namespace std;
// 抽象的成员类
class AbstractMember
{
public:
AbstractMember(string name) :m_name(name){}
string getName()
{
return m_name;
}
// 接受状态对象的访问
virtual void accept(AbstractAction* action) = 0;
virtual ~AbstractMember() {}
protected:
string m_name;
};
// 男性成员
class MaleMember : public AbstractMember
{
public:
AbstractMember::AbstractMember;
void accept(AbstractAction* action) override
{
action->maleDoing(this);
}
};
// 女性成员
class FemaleMember : public AbstractMember
{
public:
AbstractMember::AbstractMember;
void accept(AbstractAction* action) override
{
action->femalDoing(this);
}
};
int main()
{
srand(time(NULL));
vector<string> names{
"路飞", "索隆","山治", "乔巴", "弗兰奇", "乌索普", "布鲁克"
};
CaoMaoTeam* caomao = new CaoMaoTeam;
for (const auto& item : names)
{
caomao->add(new MaleMember(item));
}
caomao->add(new FemaleMember("娜美"));
caomao->add(new FemaleMember("罗宾"));
caomao->display();
delete caomao;
return 0;
}
访问者模式适用于数据结构比较稳定的系统,对于上面的例子而言就是指草帽团成员:只有男性和女性(不会再出现其它性别)。在剥离出的行为状态类中针对男性和女性提供了相对应的 doing 方法。这种模式的优势就是可以方便的给对象添加新的状态和处理动作,也就是添加新的 AbstractAction 子类(算法类),在需要的时候让这个子类去访问某个成员对象,访问者模式的最大优势就是使算法的增加变得更加容易维护。
如果不按照性别进行划分,草帽团一共9个成员就需要在行为状态类中给每个成员提供一个 doing 方法,当草帽团又添加了新的成员,状态类中也需要给新成员再添加一个对应的 doing 方法,这就破坏了设计模式的开放 – 封闭原则。
贡献者
版权所有
版权归属:PinkDopeyBug