设计模式基础(14):命令模式&访问模式
包含命令模式&访问模式两种模式中的C++示例代码、面向的问题、图解两种模式核心思想
命令模式
面向的需求
- 在软件构建的过程中,“行为请求者”和“行为实现者”通常是一种紧耦合。在一些业务场景中希望解耦这种关系。将一组行为抽象为对象。
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| #include <iostream> #include <vector> #include <string> using namespace std;
class Command { public: virtual void execute() = 0; };
class ConcreteCommand1 : public Command { string arg; public: ConcreteCommand1(const string & a) : arg(a) {} void execute() override { cout<< "#1 process..."<<arg<<endl; } };
class ConcreteCommand2 : public Command { string arg; public: ConcreteCommand2(const string & a) : arg(a) {} void execute() override { cout<< "#2 process..."<<arg<<endl; } }; class MacroCommand : public Command { vector<Command*> commands; public: void addCommand(Command *c) { commands.push_back(c); } void execute() override { for (auto &c : commands) { c->execute(); } } }; int main() {
ConcreteCommand1 command1(receiver, "Arg ###"); ConcreteCommand2 command2(receiver, "Arg $$$"); MacroCommand macro; macro.addCommand(&command1); macro.addCommand(&command2); macro.execute();
}
|
代码思想分析
- 这样的好处是什么?
- 将请求(命令)封装为一个对象,从而你可以用不同的请求对客户进行参数化;支持更多更灵活的面向对象的操作。
关键点
- 目前这种直接封装命令的方案逐渐弃用,其思想更多是通过函数对象来实现,如仿函数。
访问模式
面向的需求
当需要对已经存在的类内部做进一步的功能扩展,如何在保证代码的复用性上为其增加功能。
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| #include <iostream> using namespace std;
class Visitor; class Element { public: virtual void accept(Visitor& visitor) = 0; virtual ~Element(){} };
class ElementA : public Element { public: void accept(Visitor &visitor) override { visitor.visitElementA(*this); }
};
class ElementB : public Element { public: void accept(Visitor &visitor) override { visitor.visitElementB(*this); }
};
class Visitor{ public: virtual void visitElementA(ElementA& element) = 0; virtual void visitElementB(ElementB& element) = 0; virtual ~Visitor(){} };
class Visitor1 : public Visitor{ public: void visitElementA(ElementA& element) override{ cout << "Visitor1 is processing ElementA" << endl; } void visitElementB(ElementB& element) override{ cout << "Visitor1 is processing ElementB" << endl; } };
class Visitor2 : public Visitor{ public: void visitElementA(ElementA& element) override{ cout << "Visitor2 is processing ElementA" << endl; } void visitElementB(ElementB& element) override{ cout << "Visitor2 is processing ElementB" << endl; } };
int main() { Visitor2 visitor; ElementB elementB; elementB.accept(visitor); ElementA elementA; elementA.accept(visitor);
return 0; }
|
代码思想分析
分析
- 借助一个visitor来捕获原有的对象类型,在visitor中增加具体的功能
- 核心技术逻辑double dispatch。
- 先根据Base基类的指针对象,多态确定是谁调用的accept。
- 再根据accept传入的Visitor基类指针,多态确定具体是哪一个visitor下功能。
关键点
- 一定要注意到Base的子类类型数目一定要确定,因为这涉及到模式的稳定性。
- Double Dispatch的逻辑调用关系