23种设计模式(三)——观察者模式【组件协作】

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

文章目录

亦称事件订阅者、监听者、Event-Subscriber、Listener、Observer

意图

在许多设计中经常涉及多个对象都对一个特殊对象中的数据变化感兴趣而且这多个对象都希望跟踪那个特殊对象中的数据变化也就是说当对象间存在一对多关系时在这样的情况下就可以使用观察者模式。当一个对象被修改时则会自动通知它的依赖对象。

观察者模式是关于多个对象想知道一个对象中数据变化情况的一种成熟的模式。观察者模式中有一个称作“主题”的对象和若干个称作“观察者”的对象“主题”和“观察者”间是一种一对多的依赖关系当“主题”的状态发生变化时所有“观察者”都得到通知。

主要解决一个对象状态改变给其他对象通知的问题而且要考虑到易用和低耦合保证高度的协作。

在这里插入图片描述

什么时候使用观察者

1、当一个对象的数据更新时需要通知其他对象但这个对象又不希望和被通知的那些对象形成紧耦合。

2、当一个对象的数据更新时这个对象需要让其他对象也各自更新自己的数据但这个对象不知道具体有多少对象需要更新数据。

使用观察者模式也有两个重点问题要解决

1广播链的问题

如果你做过数据库的触发器你就应该知道有一个触发器链的问题比如表 A 上写了一个触发器内容是一个字段更新后更新表 B 的一条数据而表 B 上也有个触发器要更新表 C表 C 也有触发器…,完蛋了这个数据库基本上就毁掉了我们的观察者模式也是一样的问题一个观察者可以有双重身份即使观察者也是被观察者这没什么问题呀但是链一旦建立这个逻辑就比较复杂可维护性非常差根据经验建议在一个观察者模式中最多出现一个对象既是观察者也是被观察者也就是说消息最多转发一次传递两次这还是比较好控制的

2异步处理问题

被观察者发生动作了观察者要做出回应如果观察者比较多而且处理时间比较长怎么办那就用异步呗异步处理就要考虑线程安全和队列的问题这个大家有时间看看消息队列Message Queue就会有更深的了解。

真实世界类比

在这里插入图片描述

杂志和报纸订阅。

如果你订阅了一份杂志或报纸 那就不需要再去报摊查询新出版的刊物了。 出版社 即应用中的 “发布者” 会在刊物出版后 甚至提前 直接将最新一期寄送至你的邮箱中。

出版社负责维护订阅者列表 了解订阅者对哪些刊物感兴趣。 当订阅者希望出版社停止寄送新一期的杂志时 他们可随时从该列表中退出。

观察者模式的实现

1、IObserver类—抽象观察者为所有具体观察者定义一个接口在得到主题通知时更新自己。

这个接口叫做更新接口抽象观察者一般用一个抽象类或者一个接口实现。更新接口通常包括一个Update方法这个方法叫做更新方法。

2、ISubject类—主题或者抽象通知者一般用一个抽象类或者一个接口实现。

它把所有对观察者对象的引用保存到一个聚集里每个主题都可以有任何数量的观察者。抽象主题提供一个接口可以增加和删除观察者。

3、Subject类—具体主题或者具体通知者将有关状态存入具体观察者对象在具体主题的内部状态改变时给所有登记过的观察者发送通知。具体主题角色通常用一个具体类实现。

4、Observer类—具体观察者实现抽象观察者角色所要求的更新接口以便使本身的状态与主题的状态相协调。

具体观察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体类实现。

class IObserver {
public:
	virtual ~IObserver() {};
	virtual void Update(const std::string &message_from_subject) = 0;
};

class ISubject {
public:
	virtual ~ISubject() {};
	virtual void Attach(IObserver *observer) = 0;
	virtual void Detach(IObserver *observer) = 0;
	virtual void Notify() = 0;
};

/**
 * The Subject owns some important state and notifies observers when the state
 * changes.
 */

class Subject : public ISubject {
public:
	virtual ~Subject() {
		std::cout << "Goodbye, I was the Subject.\n";
	}

	/**
	 * The subscription management methods.
	 */
	void Attach(IObserver *observer) override {
		list_observer_.push_back(observer);
	}
	void Detach(IObserver *observer) override {
		list_observer_.remove(observer);
	}
	void Notify() override {
		std::list<IObserver *>::iterator iterator = list_observer_.begin();
		HowManyObserver();
		while (iterator != list_observer_.end()) {
			(*iterator)->Update(message_);
			++iterator;
		}
	}

	void CreateMessage(std::string message = "Empty") {
		this->message_ = message;
		Notify();
	}
	void HowManyObserver() {
		std::cout << "There are " << list_observer_.size() << " observers in the list.\n";
	}

	/**
	 * Usually, the subscription logic is only a fraction of what a Subject can
	 * really do. Subjects commonly hold some important business logic, that
	 * triggers a notification method whenever something important is about to
	 * happen (or after it).
	 */
	void SomeBusinessLogic() {
		this->message_ = "change message message";
		Notify();
		std::cout << "I'm about to do some thing important\n";
	}

private:
	std::list<IObserver *> list_observer_;
	std::string message_;
};

class Observer : public IObserver {
public:
	Observer(Subject &subject) : subject_(subject) {
		this->subject_.Attach(this);
		std::cout << "Hi, I'm the Observer \"" << ++Observer::static_number_ << "\".\n";
		this->number_ = Observer::static_number_;
	}
	virtual ~Observer() {
		std::cout << "Goodbye, I was the Observer \"" << this->number_ << "\".\n";
	}

	void Update(const std::string &message_from_subject) override {
		message_from_subject_ = message_from_subject;
		PrintInfo();
	}
	void RemoveMeFromTheList() {
		subject_.Detach(this);
		std::cout << "Observer \"" << number_ << "\" removed from the list.\n";
	}
	void PrintInfo() {
		std::cout << "Observer \"" << this->number_ << "\": a new message is available --> " << this->message_from_subject_ << "\n";
	}

private:
	std::string message_from_subject_;
	Subject &subject_;
	static int static_number_;
	int number_;
};

观察者模式的优缺点

优点缺点
具体主题和具体观察者是松耦合关系。如果一个被观察者对象有很多的直接和间接的观察者的话将所有的观察者都通知到会花费很多时间。
观察者模式满足“开-闭原则”。主题接口仅仅依赖于观察者接口。如果在观察者和观察目标之间有循环依赖的话观察目标会触发它们之间进行循环调用可能导致系统崩溃。
观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的而仅仅只是知道观察目标发生了变化。
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6