“增加一层间接层”是软件系统中对许多复杂问题的一种常见解决方案。在面向对象系统中,直接食用某些对象会带来很多问题,作为间接层的proxy对象便是解决这一问题的常见手段。
2.伪代码:
class ISubject{
public:
virtual void process();
};
//Proxy的设计
class SubjectProxy: public ISubject{
public:
virtual void process(){
//对RealSubject的一种间接访问
//....
}
};
class ClientApp{
ISubject* subject;
public:
ClientApp(){
subject=new SubjectProxy();
}
void DoTask(){
//...
subject->process();
//....
}
};
3.理解:
copy on write就是这个思想。看类图以及代码简单,但是它真正的实现可能会很复杂。
4.类图:
需要将一些现存的对象放在新的环境中应用,但是新环境要求的接口是这些现存对象所不能满足的。如何应对这种迁移的变化?如何既能利用现存对象的良好实现,同时又能满足新的应用环境的要求接口?
2.伪代码:
//目标接口(新接口)
class ITarget{
public:
virtual void process()=0;
};
//遗留接口(老接口)
class IAdaptee{
public:
virtual void foo(int data)=0;
virtual int bar()=0;
};
//遗留类型
class OldClass: public IAdaptee{
//....
};
//对象适配器
class Adapter: public ITarget{ //继承
protected:
IAdaptee* pAdaptee;//组合
public:
Adapter(IAdaptee* pAdaptee){
this->pAdaptee=pAdaptee;
}
virtual void process(){
int data=pAdaptee->bar();
pAdaptee->foo(data);
}
};
//类适配器
class Adapter: public ITarget,
protected OldClass{ //多继承
}
int main(){
IAdaptee* pAdaptee=new OldClass();
ITarget* pTarget=new Adapter(pAdaptee);
pTarget->process();
}
class stack{
deqeue container;
};
class queue{
deqeue container;
};
3.类图:
会出现多个对象互相交互的情况,对象之间通常会维持一种复杂的引用关系,如果遇到一些需求的更改,这种直接的引用关系将会面临不断变化。
2.伪代码:
与facade相同,思想,无代码
3.理解:
Colleague和Mediator两个类之间相互依赖,Colleague之间不相互依赖,但是会通过Mediator间接依赖。把直接依赖关系变为间接依赖关系。facade用于解耦内部与外部之间的关系,中介者相当于解耦facade内部之间的关系。
4.类图:
在组件变化构建过程中,某些对象的状态经常面临变化,如何对这些变化进行有效的管理?同时又维持高层模块的稳定?
某些对象的状态如果改变,其行为也会随之改变。如何在运行时根据对象的状态来透明的更改对象的行为?而不会为对象操作和状态转变之间引入紧耦合?
2.伪代码:
class NetworkState{
public:
NetworkState* pNext;
virtual void Operation1()=0;
virtual void Operation2()=0;
virtual void Operation3()=0;
virtual ~NetworkState(){}
};
class OpenState :public NetworkState{
static NetworkState* m_instance;
public:
static NetworkState* getInstance(){
if (m_instance == nullptr) {
m_instance = new OpenState();
}
return m_instance;
}
void Operation1(){
//**********
pNext = CloseState::getInstance();
}
void Operation2(){
//..........
pNext = ConnectState::getInstance();
}
void Operation3(){
//$$$$$$$$$$
pNext = OpenState::getInstance();
}
};
class CloseState:public NetworkState{ }
//...
class NetworkProcessor{
NetworkState* pState;
public:
NetworkProcessor(NetworkState* pState){
this->pState = pState;
}
void Operation1(){
//...
pState->Operation1();
pState = pState->pNext;
//...
}
void Operation2(){
//...
pState->Operation2();
pState = pState->pNext;
//...
}
void Operation3(){
//...
pState->Operation3();
pState = pState->pNext;
//...
}
};
某些对象的状态在转化过程中,可能有某种需要,要求程序能够回溯到对象之前处于某个点时的状态。如何在不破坏封装性的前提下实现这个任务呢?
2.伪代码:
class Memento
{
string state;
//..
public:
Memento(const string & s) : state(s) {}
string getState() const { return state; }
void setState(const string & s) { state = s; }
};
class Originator
{
string state;
//....
public:
Originator() {}
Memento createMomento() {
Memento m(state);
return m;
}
void setMomento(const Memento & m) {
state = m.getState();
}
};
int main()
{
Originator orginator;
//捕获对象状态,存储到备忘录
Memento mem = orginator.createMomento();
//... 改变orginator状态
//从备忘录中恢复
orginator.setMomento(mem);
}
3.理解:
备忘录就是存储一个类的状态快照,在需要的时候设置为备忘录中的状态。核心是隐藏信息。这个模式有些过时。其实就是对象序列化。
4.类图:
一些组件在内部具有特定的数据结构,如果让客户程序依赖于这些特定的数据结构,将破坏组件的复用性。这个时候,将这些数据结构封装在内部,对外提供统一的接口,来实现与特定的数据结构无关的访问。
如何将客户代码与复杂的对象容器结构解耦?让对象容器自己实现自身的复杂结构,从而使得客户代码就像处理简单对象一样来处理复杂的对象容器?
2.伪代码:
#include
#include
#include
#include
using namespace std;
class Component
{
public:
virtual void process() = 0;
virtual ~Component(){}
};
//树节点
class Composite : public Component{
string name;
list elements;
public:
Composite(const string & s) : name(s) {}
void add(Component* element) {
elements.push_back(element);
}
void remove(Component* element){
elements.remove(element);
}
void process(){
//1. process current node
//2. process leaf nodes
for (auto &e : elements)
e->process(); //多态调用
}
};
//叶子节点
class Leaf : public Component{
string name;
public:
Leaf(string s) : name(s) {}
void process(){
//process current node
}
};
void Invoke(Component & c){
//...
c.process();
//...
}
int main()
{
Composite root("root");
Composite treeNode1("treeNode1");
Composite treeNode2("treeNode2");
Composite treeNode3("treeNode3");
Composite treeNode4("treeNode4");
Leaf leaf1("left1");
Leaf leaf2("left2");
root.add(&treeNode1);
treeNode1.add(&treeNode2);
treeNode2.add(&leaf1);
root.add(&treeNode3);
treeNode3.add(&treeNode4);
treeNode4.add(&leaf2);
process(root);
process(leaf2);
process(treeNode3);
}
3.理解:
对象组合成树形结构。和装饰器有点像,不仅has-a,而且is-a。将一对多的关系替换成一对一的关系。
4.类图:
提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。
2.伪代码:
template
class Iterator
{
public:
virtual void first() = 0;
virtual void next() = 0;
virtual bool isDone() const = 0;
virtual T& current() = 0;
};
template
class MyCollection{
public:
Iterator GetIterator(){
//...
}
};
template
class CollectionIterator : public Iterator{
MyCollection mc;
public:
CollectionIterator(const MyCollection & c): mc(c){ }
void first() override {
}
void next() override {
}
bool isDone() const override{
}
T& current() override{
}
};
void MyAlgorithm()
{
MyCollection mc;
Iterator iter= mc.GetIterator();
for (iter.first(); !iter.isDone(); iter.next()){
cout << iter.current() << endl;
}
}
3.理解:
对C++来说,面向对象的迭代器已经过时了。STL中的迭代器是泛型编程思想。运行时绑定是没有编译时绑定效率高的。
4.类图:
一个请求可能有多个接收者,但是真正的接受者,也就是去处理这个请求的只有一个。这时,请求发送者与接受者的耦合可能出现变化脆弱的情况。
2.伪代码:
#include
#include
using namespace std;
enum class RequestType
{
REQ_HANDLER1,
REQ_HANDLER2,
REQ_HANDLER3
};
class Reqest
{
string description;
RequestType reqType;
public:
Reqest(const string & desc, RequestType type) : description(desc), reqType(type) {}
RequestType getReqType() const { return reqType; }
const string& getDescription() const { return description; }
};
class ChainHandler{
ChainHandler *nextChain;
void sendReqestToNextHandler(const Reqest & req)
{
if (nextChain != nullptr)
nextChain->handle(req);
}
protected:
virtual bool canHandleRequest(const Reqest & req) = 0;
virtual void processRequest(const Reqest & req) = 0;
public:
ChainHandler() { nextChain = nullptr; }
void setNextChain(ChainHandler *next) { nextChain = next; }
void handle(const Reqest & req)
{
if (canHandleRequest(req))
processRequest(req);
else
sendReqestToNextHandler(req);
}
};
class Handler1 : public ChainHandler{
protected:
bool canHandleRequest(const Reqest & req) override
{
return req.getReqType() == RequestType::REQ_HANDLER1;
}
void processRequest(const Reqest & req) override
{
cout << "Handler1 is handle reqest: " << req.getDescription() << endl;
}
};
class Handler2 : public ChainHandler{
protected:
bool canHandleRequest(const Reqest & req) override
{
return req.getReqType() == RequestType::REQ_HANDLER2;
}
void processRequest(const Reqest & req) override
{
cout << "Handler2 is handle reqest: " << req.getDescription() << endl;
}
};
class Handler3 : public ChainHandler{
protected:
bool canHandleRequest(const Reqest & req) override
{
return req.getReqType() == RequestType::REQ_HANDLER3;
}
void processRequest(const Reqest & req) override
{
cout << "Handler3 is handle reqest: " << req.getDescription() << endl;
}
};
int main(){
Handler1 h1;
Handler2 h2;
Handler3 h3;
h1.setNextChain(&h2);
h2.setNextChain(&h3);
Reqest req("process task ... ", RequestType::REQ_HANDLER3);
h1.handle(req);
return 0;
}
3.理解:
应用的不多。使得多个接收者都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理请求为止。
4.类图:
在组件的构建过程中,组件行为的变化经常导致组件本身的剧烈变化。下面的模式将组件本身和组件的行为进行解耦
如何将行为请求者和行为实现者解耦?
2.伪代码:
#include
#include
#include
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..."< 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();
}
3.理解:
有点和仿函数思想类似。将一个请求封装成一个对象,从而使你可用不同的请求对客户进行参数化。
4.类图:
在软件构件的过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为,如果直接在基类中作出修改,将会给子类带来繁重的变更负担,甚至破坏原有设计。
2.伪代码:
#include
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(){}
};
//==================================
//扩展1
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;
}
};
//扩展2
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);// double dispatch
ElementA elementA;
elementA.accept(visitor);
return 0;
}
3.理解:
Visitor中要求具体的Element稳定,这个条件通常很难保证,这是这个模式的重大缺点。accept方法表示接受一个visitor,这个visitor能够为该类增添新的方法。一般不用,因为前提条件很苛刻。
Visitor通过双重分发来实现不更改Element层次结构的前提下,在运行时透明的为类层次结构上的各个类添加新的操作。
适用于:Element类层次结构稳定,而其中的操作确实频繁改动的。(设计思想:有动的,有不动的)
4.类图:
某些领域,变化虽然频繁,但是可以抽象为某种规则。要给出该领域下的对于变化的一般性解决方案。
如果特定领域的某一问题比较复杂,类似的结构不断出现,如果使用普通的编程方式来实现将会面临非常频繁的变化。在这种情况下,将特定领域的问题表达为某种语法规则下的句子,然后构建一个解释器来解释这样的句子,从而达到解决问题的目的。
2.伪代码:
#include
#include
3.理解:
可以理解为四则运算的运算树。使用场景为:业务规则频繁变化,且类似的结构重复出现,并且容易(简单简单,小而简单的问题)抽象为有规则的问题。
4.类图:
参考文章:侯捷C++八部曲笔记(三、设计模式)_侯捷c++设计模式-CSDN博客