概念:软件设计模式(Design pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。
开闭原则
此原则是由"Bertrand Meyer"提出的。原文是:“Software entities should be open for extension,but closed for modification”。就是说模块应对扩展开放,而对修改关闭。模块应尽量在不修改原(是"原",指原来的代码)代码的情况下进行扩展。
里氏替换原则
里氏代换原则是由"Barbara Liskov"提出的。如果调用的是父类的话,那么换成子类也完全可以运行。
合成复用原则
就是说要少用继承,多用合成关系来实现。
依赖倒转原则
依赖于抽象,不能依赖于具体实现
接口隔离原则
类之间的依赖关系应该建立在最小的接口上
单一职责原则
一个类只负责一个功能领域中的相应职责
迪米特法则
一个软件实体应当尽可能少的与其他实体发生相互作用
模式名称==
一个助记名,它用一两个词来描述模式的问题、解决方案和效果。命名一个新的模式增加了我们的设计词汇。找到恰当的模式名也是我们设计模式编目工作的难点之一。
问题
描述问题存在的前因后果,它可能描述了特定的设计问题,如怎样用对象表示算法等。也可能描述了导致不灵活设计的类或对象结构。有时候,问题部分会包括使用模式必须满足的一系列先决条件。
解决方案
描述了设计的组成成分,它们之间的相互关系及各自的职责和协作方式。
效果
描述了模式应用的效果及使用模式应权衡的问题。
设计模式总共有23种,根据目的准则分类,分为三大类。
创建型设计模式(顾名思义就是和对象的创建有关,共5种):单例模式,工厂方法模式,抽象工厂模式,建造者模式,原型模式。
结构型设计模式(从程序的结构上解决模块之间的耦合问题,共7种):适配器模式,装饰者模式,代理模式,外观模式,桥接模式,组合模式,享元模式。
行为型设计模式(处理类或者对象如何交互,如何分配职责,11种):策略模式,模板方法模式,观察者模式,迭代器模式,责任链模式,命令模式,备忘录模式,状态模式,访问者模式,中介者模式,解释器模式。
观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
主要关注的是对象一对多的关系,也就是多个对象依赖于一个对象,当该对象的状态发生变化时,其他对象也会收到通知。
形象地说,一组数据可以画出不同的图,当这组数据发生变化时,相应的图也会发生变化。
这个明星他是主题对象,许多粉丝关注了他。粉丝就是观察者。当明星有微博发出的时候,他会通知所有他的粉丝。他的所有粉丝就会收到。
1)Subject:抽象主题,他把所有观察者对象保存在一个集合里,可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。意思就是明星把所有的粉丝都保存在一个账号里面,粉丝数量不限,可以新增粉丝也可以拉黑粉丝。
(2)ConcreteSubject:具体主题,该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。意思是我们的明星一有动态,就会把消息给粉丝。
(3)Observer:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。这就是我们所有粉丝的抽象。
(4)ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。具体每一个粉丝。
第一、观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体观察者列表,每一个具体观察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。
由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。如果被观察者和观察者都被扔到一起,那么这个对象必然跨越抽象化和具体化层次。
第二、观察者模式支持广播通讯。被观察者会向所有的登记过的观察者发出通知。
第一、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间
第二、如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察者模式是要特别注意这一点。
第三、虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。
当一个对象的改变需要同时改变其他对象,而且,它不知道具体有多少对象有待改变时,应该考虑使用观察者模式。
当一个抽象模型有两个方面,其中一方面依赖于另一方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。
总的来讲,观察者模式所做的工作其实就是在解除耦合。让耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不会影响另一边的变化。——这是依赖倒转原则的最佳体现!
#include
#include
#include
#include
#include
#include
using namespace std;
// 观察者抽象类
class Observer
{
public:
// 处理消息的接口
virtual void handle(int msgid) = 0;
};
// 第一个观察者实例
class Observer1 : public Observer
{
public:
void handle(int msgid)
{
switch (msgid)
{
case 1:
cout << "Observer1 recv 1 msg!" << endl;
break;
case 2:
cout << "Observer1 recv 2 msg!" << endl;
break;
default:
cout << "Observer1 recv unknow msg!" << endl;
break;
}
}
};
// 第二个观察者实例
class Observer2 : public Observer
{
public:
void handle(int msgid)
{
switch (msgid)
{
case 2:
cout << "Observer2 recv 2 msg!" << endl;
break;
default:
cout << "Observer2 recv unknow msg!" << endl;
break;
}
}
};
// 第三个观察者实例
class Observer3 : public Observer
{
public:
void handle(int msgid)
{
switch (msgid)
{
case 1:
cout << "Observer3 recv 1 msg!" << endl;
break;
case 3:
cout << "Observer3 recv 3 msg!" << endl;
break;
default:
cout << "Observer3 recv unknow msg!" << endl;
break;
}
}
};
// 主题类
class Subject
{
public:
// 给主题增加观察者对象
void addObserver(Observer* obser, int msgid)
{
_subMap[msgid].push_back(obser);
/*auto it = _subMap.find(msgid);
if (it != _subMap.end())
{
it->second.push_back(obser);
}
else
{
list lis;
lis.push_back(obser);
_subMap.insert({ msgid, lis });
}*/
}
// 主题检测发生改变,通知相应的观察者对象处理事件
void dispatch(int msgid)
{
auto it = _subMap.find(msgid);
if (it != _subMap.end())
{
for (Observer *pObser : it->second)
{
pObser->handle(msgid);
}
}
}
private:
unordered_map<int, list<Observer*>> _subMap;
};