设计模式(四)

行为模型设计模式

策略模式:

定义了算法家族分别封装起来,让他们之间可以相互替换,此模式使算法的变化不会影响到使用算法的客户。(将每一个算法策略封装到接口中,根据需要设定的策略,使具体实现和策略解耦)

策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法都是完成相同的工作只是实现不同,他们可以以相同的方式调用所有方法,减少各类算法类之间的耦合。

策略模式的优缺点:优点是定义算法族使用继承可以把公共的代码移到父类中,提高复用性;算法的变化和客户端分离,提高可扩展性。缺点:可能导致类过多,每个具体策略类都会产生一个新类,客户端必须知道所有的策略类,并自行决定使用哪一个策略类。

刘备取西川,庞军师献出三种上中下三种策略供刘备选择,当然目的就一个攻取西川。

cpp 复制代码
#include <iostream>
#include <memory>
using namespace std;
class seizeSiChuan
{
public:
	virtual ~seizeSiChuan() = default;
	virtual string attackSiChuan(const string &msg) const = 0;
};
// 上计
class BestPolicy : public seizeSiChuan
{
public:
	explicit BestPolicy(const string &str)
		: PolicyInfo(str)
	{
	}
	string attackSiChuan(const string &msg) const override
	{
		cout << msg << "庞统军师的上计 " << PolicyInfo << " 刘备觉上计未免太急" << endl;
		return "NO";
	}

private:
	string PolicyInfo;
};
// 中计
class MiddlePolicy : public seizeSiChuan
{
public:
	explicit MiddlePolicy(const string &str)
		: PolicyInfo(str)
	{
	}

	string attackSiChuan(const string &msg) const override
	{
		cout << msg << "庞统军师的中计 " << PolicyInfo << "刘备觉中计不快不慢,正得其宜,可以行之" << endl;
		return "OK";
	}

private:
	string PolicyInfo;
};

// 下计
class LowerPolicy : public seizeSiChuan
{
public:
	explicit LowerPolicy(const string &str)
		: PolicyInfo(str)
	{
	}
	string attackSiChuan(const string &msg) const override
	{
		cout << msg << "庞统军师的下计 " << PolicyInfo << "刘备觉下计又觉太缓" << endl;
		return "NO";
	}

private:
	string PolicyInfo;
};
// 考虑选择
class makeContext
{
public:
	explicit makeContext(seizeSiChuan *m_contest)
		: mcontest(m_contest) {}

	~makeContext()
	{
		if (mcontest != nullptr)
		{
			delete mcontest;
			mcontest = nullptr;
		}
	}
	string attackSiChuan(const string &msg) const
	{
		if (mcontest != nullptr)
		{
			return mcontest->attackSiChuan(msg);
		}
		else
		{
			return "NO";
		}
	}

private:
	seizeSiChuan *mcontest = nullptr;
};
// 你是刘备决定选取哪种策略
int main()
{
	while (true)
	{
		unique_ptr<makeContext> context(nullptr);
		char s;
		cin >> s;
		if (s == 'B')
		{ // 上计
			context.reset(new makeContext(new BestPolicy("上计:点兵出其不意直接攻打 ")));
		}
		else if (s == 'M')
		{ // 中策
			context.reset(new makeContext(new MiddlePolicy("中计:使用类似于假途灭虢之计 ")));
		}
		else if (s == 'L')
		{ /// 下策
			context.reset(new makeContext(new LowerPolicy("下计:罢兵回荆州后徐图缓取之 ")));
		}
		if (context != nullptr)
		{
			if (context->attackSiChuan("夺取西川选择了") == "OK")
			{
				cout << "英雄所见略同,就这么定了" << endl;
				break;
			}
			else
			{
				cout << "英雄所见非同,可再行商议" << endl;
			}
		}
		else
		{
			cout << "只有上中下三种策略";
		}
	}
}

策略可以可以自由切换,避免使用多重条件判断。但是策略类增多并且所有策略类都需要对外暴露。

模板模式:

定义了一个操作中定义一个算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变算法结构即可以重新定义算法某些特定步骤。

模板方法模式是通过把不变的行为搬到超类里,去除子类重复代码体现其优势,模板方法体现的就是一个很好的复用平台。当不变和可变的行为在方法的子类实现中混合在一起的时候不变的行为就会在子类中重复出现,通过模板方法模式把这些行为移到单一的地方这样就帮助子类摆脱重复的不变行为的纠缠。

使用场景:需要实现算法不变的部分,将可变的部分留给子类;各个子类中的公共行为提取出来并集中到一个公共父类避免代码重用;通过子类来决定父类算法中的某个步骤是否执行,实现子类对父类的反向控制。

比如:一道《鲜虾仁》不同厨师有不同的做法。总体且将其分为厨师处理+上菜+请品尝,公共部分可以放在抽象类里,至于厨师如何处理就看各自的方式。

cpp 复制代码
#include <iostream>
#include <memory>

class chef
{
public:
	virtual ~chef() = default;
	chef(const std::string &str) :chefName(str){

	}
	void TemplateMethod()
	{
		std::cout << chefName <<std::endl;
		step1();
		step2();
		step3();
	}
protected:
	virtual void step1()const = 0;
	virtual void step2()const = 0;
	virtual void step3(){
		std::cout<<"请品尝"<<std::endl;
	}
private:
    std::string chefName;
};

class chefA : public chef
{
	public:
    // 构造函数传递咖啡名称
    chefA() : chef("广东黄师傅:") {}

protected:
	virtual void step1()const override
	{
		std::cout << "<鲜虾仁>步骤: 生腌食材---";
	}

	virtual void step2()const override
	{
		std::cout << "摆碗上菜--- ";
	}

};

class chefB : public chef
{
	public:
	chefB() : chef("上海刘师傅:") {}
protected:
	virtual void step1()const override
	{
		std::cout << "<鲜虾仁>步骤: 蒸煮+蘸料---";
	}
	virtual void step2()const override
	{
		std::cout << "装盘上菜--- ";
	}
};

int main()
{
	std::unique_ptr<chef> cf = std::make_unique<chefA>();
	cf->TemplateMethod();
	cf.reset(new chefB());
	cf->TemplateMethod();
	return 0;
}

模板模式获得一种反向控制结构效果,体现了依赖倒置原则,就是父类调用子类的操作(高层调用低层的操作)低层模块实现高层模块声明的接口。这样控制权在父类,低层模块反而要依赖高层模块。但是因为模板模式采用继承这种强制约束关系,导致复用性不高。比如果改做汤TemplateMethod里面的步骤就不合适了,我们就无法再次使用这个模板了,这样就导致了不能复用子类的实现步骤。

观察者模式:

定义了一种一对多的依赖关系让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有观察者对象并自动更新。

特点:观察者模式关键对象是主题subject和观察者observer,一个主题可以有任意数目的依赖它的observer,当subject发生变化时所有observer都可以得到通知,subject发出通知时并不需要知道它的观察者,具体观察者是谁它根本不知道,而任何一个具体观察者并不知道也不需要知道其他观察者的存在。观察者所作的就是解除耦合,让耦合的双方都依赖于抽象不依赖于具体,从而使得各自的变化不会影响另一边的变化。

使用场景:当一个对象的改变需要同时改变其他对象且不知道有多少对象有待改变时,考虑使用观察者模式。

比如微信公众号:‌微信公众号是主题对象 ‌,它负责发布内容并通知订阅者;‌微信用户是观察者 ‌,他们订阅公众号以接收更新。当‌公众号的内容更新时‌,所有订阅的用户都会收到通知,这体现了观察者模式的"当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并进行更新"的原则。此外,观察者模式还允许订阅者根据自己的需要选择是否接收通知,这与微信公众号中用户可以取消订阅的功能相吻合。这种灵活性是观察者模式的一个重要特点,它使得系统可以根据环境的变化动态地调整其行为‌。

不足:如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知会造成资源浪费;如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃;观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>

// 观察者接口
class Observer
{
public:
	virtual void update(std::string &msg) = 0;
	virtual ~Observer() = default;
};

// 主题接口
class Subject
{
public:
	virtual void registerObserver(Observer *observer) = 0;
	virtual void removeObserver(Observer *observer) = 0;
	virtual void notifyObservers() = 0;
	virtual ~Subject() = default;
};

// 具体主题实现
class takeAction : public Subject
{
private:
	std::vector<Observer *> observers;
	std::string msg;

public:
	takeAction() : msg("") {}
	void registerObserver(Observer *observer) override
	{
		observers.push_back(observer);
	}
	void removeObserver(Observer *observer) override
	{
		auto it = std::find(observers.begin(), observers.end(), observer);
		if (it != observers.end())
		{
			observers.erase(it);
		}
	}
	void notifyObservers() override
	{
		for (Observer *observer : observers)
		{
			observer->update(msg);
		}
	}
	// 添加获取观察者的函数
	const std::vector<Observer *> &getObservers() const
	{
		return observers;
	}

	void KongMingSignal(char c)
	{
		if (c == 'O')
		{
			msg = "收到火起信号,进攻";
			notifyObservers();
		}
		else
		{
			msg = "收到火熄信号,偃旗息鼓";
			notifyObservers();
		}
	}
};

// 具体观察者实现
class ObserverGeneral : public Observer
{
private:
	std::string name;

public:
	ObserverGeneral(const std::string &name) : name(name) {}

	void update(std::string &msg) override
	{
		std::cout << name << " " << msg << std::endl;
	}
};

int main()
{
	takeAction takeAction;
	takeAction.registerObserver(new ObserverGeneral("关羽"));
	takeAction.registerObserver(new ObserverGeneral("张飞"));
	Observer* ObserverGeneralA = new ObserverGeneral("赵云");
	takeAction.registerObserver(ObserverGeneralA);
	char updates;
	std::cin >> updates;
	takeAction.KongMingSignal(updates);
	takeAction.removeObserver(ObserverGeneralA);
	takeAction.KongMingSignal(updates);
	// 释放动态分配的观察者对象
	for (Observer *observer : takeAction.getObservers())
	{
		delete observer;
	}

	return 0;
}

迭代器模式:

提供一种方法顺序访问一个聚合对象中各个元素,而不暴露该对象的内部的结构。

使用场景:当需要访问一个聚合对象而且不管这些对象是什么都需要遍历的时候,就应该选择使用迭代器模式。

cpp 复制代码
#include <iostream>
#include <vector>

// 迭代器接口
class Iterator {
public:
    virtual int next() = 0;
    virtual bool hasNext() = 0;
};

// 具体迭代器
class ConcreteIterator : public Iterator {
private:
    std::vector<int> data;
    int position;

public:
    ConcreteIterator(std::vector<int> vec) : data(vec), position(0) {}

    int next() override {
        return data[position++];
    }

    bool hasNext() override {
        return position < data.size();
    }
};

// 聚合对象接口
class Aggregate {
public:
    virtual Iterator* createIterator() = 0;
};

// 具体聚合对象
class ConcreteAggregate : public Aggregate {
private:
    std::vector<int> data;

public:
    void addData(int value) {
        data.push_back(value);
    }

    Iterator* createIterator() override {
        return new ConcreteIterator(data);
    }
};

int main() {
    ConcreteAggregate aggregate;
    aggregate.addData(1);
    aggregate.addData(2);
    aggregate.addData(3);

    Iterator* iterator = aggregate.createIterator();
    while (iterator->hasNext()) {
        std::cout << iterator->next() << " ";
    }
    delete iterator;
    return 0;
}

实例主要包括:

  1. 迭代器(Iterator):定义了访问和遍历元素的接口。
  2. 具体迭代器(Concrete Iterator):实现迭代器接口,对集合进行具体的迭代操作。
  3. 聚合对象(Aggregate):定义创建相应迭代器对象的接口。
  4. 具体聚合对象(Concrete Aggregate):实现聚合对象接口,返回一个具体迭代器的实例。

责任链模式:

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这个对象连成一条链,将请求沿着这条链传递,直到有对象处理它为止。

优点:解耦:请求发起者和接收者都没有明确信息,且链中的对象自己并不知道链的结构,职责链可以简化对象的相互连接,仅需要保持一个指向其后继的引用,不需要保持它所有的候选者的引用。灵活性增强:可以动态改变处理请求的顺序和组合,

不足:由于请求需要依次通过链中的所有对象,因此在处理请求时可能会影响性能,特别是在链中有大量节点时。调试困难:当请求在链中传递时,可能会变得难以跟踪和调试,特别是在复杂的链条中。如果责任链的末端没有对象能够处理请求,那么请求可能会一直传递到链的末端,导致请求无法被处理。

cpp 复制代码
#include <iostream>
#include <memory>
class Handler
{
public:
    virtual ~Handler() = default;
    virtual void setNextHandler(Handler *nextHandler) = 0;
    virtual void HandlerRequest(int request) = 0;
};

class ConcreteHandler1 : public Handler
{
public:
    void HandlerRequest(int request) override
    {
        if (request < 10)
        {
            std::cout << "ConcreteHandler1 handle the number " << request << " request" << std::endl;
        }
        else if (nextHandler != nullptr)
        {
            nextHandler->HandlerRequest(request);
        }
    }
    void setNextHandler(Handler *nextHandler) override
    {
        this->nextHandler = nextHandler;
    }

private:
    Handler *nextHandler;
};
class ConcreteHandler2 : public Handler
{
public:
    void HandlerRequest(int request) override
    {
        if (request >= 10 && request < 20)
        {
            std::cout << "ConcreteHandler2 handle the number " << request << " request" << std::endl;
        }
        else if (nextHandler != nullptr)
        {
            nextHandler->HandlerRequest(request);
        }
    }
    void setNextHandler(Handler *nextHandler) override
    {
        this->nextHandler = nextHandler;
    }

private:
    Handler *nextHandler;
};

int main()
{
    ConcreteHandler1 handler1;
    ConcreteHandler2 handler2;
    handler1.setNextHandler(&handler2);
    handler1.HandlerRequest(5);
    handler1.HandlerRequest(15);
    handler1.HandlerRequest(25);
    return 0;
}

如果请求的值为5,ConcreteHandler1将处理请求;如果请求的值为15,ConcreteHandler2将处理请求。如果没有处理者能够处理请求,请求将被忽略。

命令模式:

将一个请求封装成一个对象,从而可以使用不同的请求,从而可以用不同的请求对客户进行参数化,对请求排队或者日志请求记录、以及支持可撤销的操作。

优势:命令模式将请求发送者和接收者解耦,只需知道如何发送命令不关心如何执行命令,降低耦合度。可扩展性 :容易地添加新的命令,而无需修改现有的代码,符合开闭原则。支持撤销和重做 :通过保存命令的历史记录,可以实现撤销和重做操作,提高系统的灵活性。支持队列请求 :可以将命令对象存储在队列中,实现请求的排队和延迟执行。日志记录:可以记录命令对象,实现日志记录和回放功能。

缺点:可能会导致系统中产生过多的命令对象,影响系统的性能;使用命令模式可能会使系统变得更加复杂。

cpp 复制代码
#include <iostream>
#include <memory>
// 命令接收者
class Receiver
{
public:
    void action()
    {
        std::cout << "执行命令" << std::endl;
    }
    void undoAction()
    {
        std::cout << "拒不执行" << std::endl;
    }
};
// 命令基类
class Command
{
public:
    virtual void execute() = 0;
    virtual void undo() = 0;
};
// 具体命令类
class ConcreteCommand1 : public Command
{
public:
private:
    Receiver *receiver;

public:
    ConcreteCommand1(Receiver *receiver) : receiver(receiver) {}
    void execute()
    {
        receiver->action();
    }
    void undo()
    {
        receiver->undoAction();
    }
};

// 调用者类
class Invoker
{
private:
    Command *command;
public:
    void setCommand(Command *cmd)
    {
        command = cmd;
    }
    void executeCommand()
    {
        command->execute();
    }
    void undoCommand()
    {
        command->undo();
    }
};

int main()
{
    Receiver *receiver = new Receiver(); //士兵收到信进攻或抗命
    Command *command = new ConcreteCommand1(receiver); //传令兵传信
    Invoker *invoker = new Invoker(); //将军发号施令

    invoker->setCommand(command);
    invoker->executeCommand();
    invoker->undoCommand();

    delete receiver;
    delete command;
    delete invoker;
    return 0;
}

备忘录模式:

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到保存的状态。

优点 :‌状态保存与恢复‌:当前状态的保存与恢复这对于撤销操作或程序崩溃后的恢复非常有用。‌封装性和隔离性‌:通过备忘录模式,对象的状态被封装在备忘录对象中,不会暴露给其他对象。这保护了对象的封装性和隔离性,使得对象的状态变化对其他对象透明。

缺点: ‌内存占用‌:由于每个备忘录对象需要保存一份完整的状态,当对象的状态较多或状态改变频繁时,可能会引起较大的内存占用。性能开销‌:备忘录模式的创建、存储和恢复状态的操作可能会引起一定的性能开销,特别是在状态较大或对象较复杂的情况下。

何时使用:文本编辑器 ‌:用于保存撤销和重做操作之前的文本状态,实现撤销和恢复功能。‌游戏存档 ‌;‌事务管理 ‌:在数据库事务管理中,备忘录模式可以用于保存事务执行之前的状态,以便在需要回滚事务时可以恢复到之前的状态。‌安全监管‌:在安全监管中,备忘录模式可以用于记录系统的运行状态。

cpp 复制代码
#include <iostream>
// 负责存储 Originator 对象的状态
class Memento
{
public:
    Memento() = default;
    Memento(int state) : value(state) {}
    int GetState() const
    {
        return value;
    }

private:
    int value;
};
// 负责创建和管理备忘录
class Originator
{
public:
    void InitState()
    {
        value = 100;
    }

    void show() const
    {
        std::cout << "State " << value << std::endl;
    }

    void ChangeState()
    {
        value = 0;
    }

    void RecoveryState(const Memento &me)
    {
        value = me.GetState();
    }

    Memento SaveState() const
    {
        return Memento(value);
    }

private:
    int value = 0;
};
// 负责保存备忘录
class Caretaker
{
public:
    void SaveMemento(const Memento &me)
    {
        saveMe = me;
    }

    Memento GetMemento() const
    {
        return saveMe;
    }
private:
    Memento saveMe;
};

int main()
{
    Originator org;
    org.InitState();
    org.show();
    Caretaker ct;
    ct.SaveMemento(org.SaveState());
    org.ChangeState();
    org.show();
    org.RecoveryState(ct.GetMemento());
    org.show();
    return 0;
}

状态模式:

当一个对象的内在状态改变时允许改变其行为,对象看起来似乎改变了它的类。

状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时,把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。

优点易于扩展: 状态模式使得新状态的添加和现有状态的修改变得简单,只需添加新的状态类或修改现有状态类即可,减少了代码的耦合性易于扩展。简化条件判断促进代码组织: 状态模式可以有效地消除大量的条件分支语句封装在独立的状态类中,使代码更加清晰和易于理解和有助于代码的组织和维护。

缺点:增加类的数量: 引入了多个状态类和上下文类,可能会增加程序中的类的数量和状态过于细分,使得代码结构更加复杂。可能导致性能损失: 在状态切换频繁且状态类较多的情况下,可能会引起性能损失,需要谨慎设计状态转换逻辑。

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;
// 状态接口
class State
{
public:
	virtual void handle() = 0; // 处理状态的方法
};

// 具体状态类
class OnState : public State
{
public:
	void handle() override
	{
		cout << "Light is ON" << endl;
	}
};

class OffState : public State
{
public:
	void handle() override
	{
		cout << "Light is OFF" << endl;
	}
};

class BlinkState : public State
{
public:
	void handle() override
	{
		cout << "Light is Blinking" << endl;
	}
};

// 上下文类
class Light
{
private:
	State *state; // 当前状态
public:
	Light() : state(new OffState()) {} // 初始状态为关闭
	void setState(State *newState)
	{
		delete state;
		state = newState;
	}
	void performOperation()
	{ // 执行当前状态的操作
		state->handle();
	}
	~Light()
	{
		delete state;
	}
};

int main()
{
	Light light;
	light.performOperation();
	light.performOperation();
	light.setState(new OffState());
	light.performOperation();
	light.setState(new BlinkState());
	light.performOperation();
	return 0;
}

访问者模式:

表示一个作用于某对象结构中的各个元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

访问者模式用于在不改变已有类层次结构的前提下定义新的操作。它将操作封装到独立的访问者类中,避免了在对象类中添加新操作带来的修改。访问者模式适用于当一个对象结构包含多个类,并且你希望对这些对象应用不同的操作而又不希望修改这些类的情况。通过定义不同的访问方法,可以让访问者在不同对象上执行不同的操作,从而实现灵活的算法变化。访问者模式需要在对象结构中添加接受访问者的方法,以便访问者能够访问对象的数据。

cpp 复制代码
#include <iostream>
#include <memory>
#include <vector>

class ConcreteElementA;
class ConcreteElementB;
// 访问者基类
class Vistor
{
public:
    virtual ~Vistor() = default;
    virtual void VisitConcreteElementA(ConcreteElementA *ConcreteElementA) const = 0;
    virtual void VisitConcreteElementB(ConcreteElementB *concreteElementB) const = 0;
};
// 元素类基类
class Element
{
public:
    virtual ~Element() = default;
    virtual void Accept(const std::shared_ptr<Vistor> &vistor) = 0;
};
// 具体元素类
class ConcreteElementA : public Element
{
public:
    virtual void Accept(const std::shared_ptr<Vistor> &vistor) override
    {
        vistor->VisitConcreteElementA(this);
    }
};

class ConcreteElementB : public Element
{
public:
    virtual void Accept(const std::shared_ptr<Vistor> &vistor) override
    {
        vistor->VisitConcreteElementB(this);
    }
};
// 具体的Visitor类
class ConcreteVistorA : public Vistor
{
public:
    virtual void VisitConcreteElementA(ConcreteElementA *ConcreteElementA) const override
    {
        std::cout << "ConcreteElementA ConcreteVistorA" << std::endl;
    }

    virtual void VisitConcreteElementB(ConcreteElementB *concreteElementB) const override
    {
        std::cout << "ConcreteElementB ConcreteVistorA" << std::endl;
    }
};

class ConcreteVistorB : public Vistor
{
public:
    virtual void VisitConcreteElementA(ConcreteElementA *ConcreteElementA) const override
    {
        std::cout << "ConcreteElement-A ConcreteVistorB" << std::endl;
    }

    virtual void VisitConcreteElementB(ConcreteElementB *concreteElementB) const override
    {
        std::cout << "ConcreteElement-B ConcreteVistorB" << std::endl;
    }
};

class ObjectStructure
{
public:
    void Attach(std::shared_ptr<Element> element)
    {
        m_elements.push_back(element);
    }

    void detach(std::shared_ptr<Element> elment)
    {
        auto it = m_elements.begin();
        while (it != m_elements.end())
        {
            if (*it == elment)
            {
                it = m_elements.erase(it);
            }
            else
            {
                ++it;
            }
        }
    }

    void accept(std::shared_ptr<Vistor> vistor)
    {
        for (auto element : m_elements)
        {
            element->Accept(vistor);
        }
    }

private:
    std::vector<std::shared_ptr<Element>> m_elements;
};

int main()
{
    ObjectStructure os;
    os.Attach(std::make_shared<ConcreteElementA>());
    os.Attach(std::make_shared<ConcreteElementB>());

    std::shared_ptr<ConcreteVistorA> va = std::make_shared<ConcreteVistorA>();
    std::shared_ptr<ConcreteVistorB> vb = std::make_shared<ConcreteVistorB>();

    os.accept(va);
    os.accept(vb);

    return 0;
}

中介者模式:

中介者模式又称为调停者模式,用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

优点:简化了对象之间的交互,将各同事解耦,减少子类生成,可以简化各同事类的设计和实现。缺点: 在具体中介者类中包含了同事之间的交互细节,可能会导致具体中介者类非常复杂,使得系统难以维护。

cpp 复制代码
#include<iostream>
using namespace std;
class Mediator;
//抽象国家  
class Country    
{  
protected:    
    Mediator *pmediator; //中介  
public:  
    virtual void SetMediator(Mediator *mediator){} //设置中介  
    virtual void SendMessage(string message) {}    //向中介发信息  
    virtual void GetMessage(string message) {}     //从中介获取信息  
};  
  
//抽象中介者  
class Mediator    
{  
public:    
    virtual void Send(string message, Country *person) {}    
    virtual void SetAmerica(Country *America) {}  //让中介认识具体的对象  
    virtual void SetChina(Country *China) {}    
};  
  
//美国  
class America: public Country    
{    
public:    
    void SetMediator(Mediator *mediator) { pmediator = mediator; }    
    void SendMessage(string message) { pmediator->Send(message, this); }    
    void GetMessage(string message) { cout<<"美国收到中国的信息: "<<message; }    
};  
  
//中国  
class China: public Country    
{    
public:    
    void SetMediator(Mediator *mediator) { pmediator = mediator; }    
    void SendMessage(string message) { pmediator->Send(message, this); }    
    void GetMessage(string message) { cout<<"中国收到美国信息: "<<message; }    
};  
  
//联合国  
class UN : public Mediator    
{    
private:    
    Country *USA; //美国  
    Country *CNA; //中国  
public:    
    UN(): USA(NULL), CNA(NULL) {}    
    void SetAmerica(Country *America) { USA = America; }    
    void SetChina(Country *China) { CNA = China; }    
    void Send(string message, Country *country)     
    {    
        if(country == USA) //美国给中国发信息  
            CNA->GetMessage(message); //中国收到信息  
        else    
            USA->GetMessage(message);    
    }  
};  
  
//测试代码  
int main()    
{       
    Mediator *mediator = new UN();  
    Country *pAmerica = new America();  
    Country *pChina = new China();   
      
    mediator->SetAmerica(pAmerica);    
    mediator->SetChina(pChina);    
      
    pAmerica->SetMediator(mediator);    
    pChina->SetMediator(mediator);    
      
    pAmerica->SendMessage("中国威胁论\n");    
    pChina->SendMessage("真正威胁世界安全的是美国\n");    
      
    delete pAmerica;   
    delete pChina;   
    delete mediator;    
      
    return 0;    
}  

解释器模式:

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

优点灵活性高: 解释器模式可以灵活地扩展和改变语言的语法规则,而无需修改原有代码。易于实现语法解析: 解释器模式将语法规则表示为一个抽象语法树,便于对表达式进行分析和解释。易于扩展新的表达式: 可以通过继承或组合的方式轻松添加新的表达式,扩展语言的功能。

缺点 :性能开销: 解释器模式通常会对表达式进行解释和分析,可能会产生较大的性能开销,特别是处理复杂的语言规则时。复杂度高: 随着语法规则的复杂度增加,解释器模式的实现可能会变得复杂,维护成本也会随之提高,因此不适合复杂的语法**。**

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;
class Context
{
  public:
    void set_data(int data)
    {
        this->data = data;
    }
    void set_ret(int ret)
    {
        this->ret = ret;
    }
    int get_data()
    {
        return this->data;
    }
    int get_ret()
    {
        return this->ret;
    }
  private:
    int data;
    int ret;
};

class Expression
{
  protected:
    Context *context;
  public:
    virtual void interpret(Context *context) = 0;
};
//后置++解释器
class PlusExpression : public Expression
{
    virtual void interpret(Context *context)
    {
        int temp = context->get_data();
        temp++;
        context->set_ret(temp);
    }
};

int main()
{
    Expression *exp = nullptr;
    Context *data = nullptr;

    exp = new PlusExpression;
    data = new Context;
    data->set_data(0);
    cout << "原始数据:" << data->get_data() << endl;
    exp->interpret(data);
    data->get_ret();
    cout << "++解释后:" << data->get_ret() << endl;

    delete data;
    delete exp;
    return 0;
}
相关推荐
懒大王爱吃狼21 分钟前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
秃头佛爷1 小时前
Python学习大纲总结及注意事项
开发语言·python·学习
待磨的钝刨1 小时前
【格式化查看JSON文件】coco的json文件内容都在一行如何按照json格式查看
开发语言·javascript·json
XiaoLeisj3 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
励志成为嵌入式工程师4 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉5 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer5 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq5 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
记录成长java6 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
前端青山6 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js