您现在的位置是:首页 >其他 >常用的设计模式之二(行为型模式)网站首页其他
常用的设计模式之二(行为型模式)
观察者模式
观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当主题对象发生变化时,它的所有观察者都会收到通知并进行相应的处理。
观察者模式包含以下几个角色:
- 抽象主题(Subject):定义了被观察的对象接口,它可以增加和删除观察者对象,以及通知观察者对象。
- 具体主题(ConcreteSubject):实现了抽象主题接口,它具有添加、删除观察者对象的功能。通常是被观察的对象。
- 抽象观察者(Observer):定义了观察者接口,它具有更新数据的方法,当接收到主题通知时被调用。
- 具体观察者(ConcreteObserver):实现了观察者接口,它保存一个指向具体主题对象的引用,实现了更新数据的方法,以便自身状态与主题状态协调。
观察者模式的核心思想是:当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知并自动更新。这种模式的优点是将观察者和被观察者解耦,使得程序的扩展性和复用性更加容易,可以动态地添加和删除观察者,从而避免了代码的臃肿和复杂性。
观察者模式在实际应用中非常常见,例如在图形界面开发中,窗口、按钮等组件就可以作为被观察者,而事件监听器就可以作为观察者。此外,观察者模式还可以用于日志记录、消息队列等领域。
下面是一个C++实现的简单观察者模式案例:
#include <iostream>
#include <vector>
using namespace std;
// 抽象主题类
class Subject {
public:
virtual void attach(class Observer* observer) = 0;
virtual void detach(class Observer* observer) = 0;
virtual void notify() = 0;
};
// 具体主题类
class ConcreteSubject : public Subject {
public:
void attach(Observer* observer) override {
observers.push_back(observer);
}
void detach(Observer* observer) override {
for (auto it = observers.begin(); it != observers.end(); ++it) {
if (*it == observer) {
observers.erase(it);
break;
}
}
}
void notify() override {
for (auto observer : observers) {
observer->update();
}
}
void setState(int state) {
this->state = state;
notify();
}
int getState() const {
return state;
}
private:
vector<Observer*> observers;
int state;
};
// 抽象观察者类
class Observer {
public:
virtual void update() = 0;
};
// 具体观察者类
class ConcreteObserver : public Observer {
public:
ConcreteObserver(ConcreteSubject* subject) : subject(subject) {
subject->attach(this);
}
~ConcreteObserver() override {
subject->detach(this);
}
void update() override {
cout << "Observer received notification: " << subject->getState() << endl;
}
private:
ConcreteSubject* subject;
};
int main() {
ConcreteSubject subject;
// 添加两个观察者
ConcreteObserver observer1(&subject);
ConcreteObserver observer2(&subject);
// 改变主题状态,触发通知
subject.setState(1);
// 移除一个观察者
subject.detach(&observer2);
// 再次改变主题状态,触发通知
subject.setState(2);
return 0;
}
这个示例中,Subject 定义了主题类的接口,包括添加、删除观察者和通知观察者的方法, ConcreteSubject 继承了 Subject,并实现了具体的主题类,其中 setState 方法改变主题的状态,并调用 notify 方法通知所有观察者;Observer 定义了观察者类的接口,包括更新数据的方法; ConcreteObserver 继承了 Observer,并实现了具体的观察者类,它保存了一个指ConcreteSubject 的引用,当 ConcreteSubject 的状态发生改变时,会自动更新。
在 main 函数中,我们创建了一个 ConcreteSubject 对象,并添加了两个观察者,然后改变主题状态,触发通知。接着,我们移除了一个观察者,并再次改变主题状态,验证只有一个观察者收到了通知。
模板模式
模板模式(Template Pattern)是一种行为设计模式,它定义了一个算法的骨架,而将某些步骤延迟到子类中实现。模板模式使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
模板模式的核心思想是定义一个抽象基类,其中包含了一些算法的共性,以及一些抽象方法,这些抽象方法会在具体子类中实现。然后定义一个模板方法,其中包含了一个算法的骨架,它通过调用基类中的方法来实现算法的各个步骤。具体子类可以通过重写基类中的抽象方法来实现算法的个性化定制。
以下是一个简单的 C++ 实现示例:
#include <iostream>
using namespace std;
// 抽象类
class AbstractClass {
public:
virtual void primitiveOperation1() = 0;
virtual void primitiveOperation2() = 0;
void templateMethod() {
primitiveOperation1();
primitiveOperation2();
}
};
// 具体类A
class ConcreteClassA : public AbstractClass {
public:
void primitiveOperation1() override {
cout << "ConcreteClassA::primitiveOperation1()" << endl;
}
void primitiveOperation2() override {
cout << "ConcreteClassA::primitiveOperation2()" << endl;
}
};
// 具体类B
class ConcreteClassB : public AbstractClass {
public:
void primitiveOperation1() override {
cout << "ConcreteClassB::primitiveOperation1()" << endl;
}
void primitiveOperation2() override {
cout << "ConcreteClassB::primitiveOperation2()" << endl;
}
};
int main() {
AbstractClass* a = new ConcreteClassA;
a->templateMethod();
AbstractClass* b = new ConcreteClassB;
b->templateMethod();
return 0;
}
在这个示例中,AbstractClass 是抽象基类,其中包含了一个模板方法 templateMethod,它通过调用两个抽象方法 primitiveOperation1 和 primitiveOperation2 实现算法的骨架。ConcreteClassA 和 ConcreteClassB 继承自 AbstractClass,并分别实现了自己的具体算法,即实现 primitiveOperation1 和 primitiveOperation2。
在 main 函数中,我们先创建了一个 ConcreteClassA 对象,并调用了其 templateMethod 方法,它的具体算法是先执行 primitiveOperation1,然后执行 primitiveOperation2。接着,我们创建了一个 ConcreteClassB 对象,同样调用了其 templateMethod 方法,其具体算法和 ConcreteClassA 有所不同。
模板模式的优点在于它使得算法的框架和具体实现分离,降低了实现算法的难度和维护成本,并且可以在不改变算法结构的情况下,方便地扩展和修改算法的具体实现。模板模式还可以提高代码的复用性,避免了代码重复。
模板模式的缺点在于它需要定义抽象类和具体类,这样就增加了代码的复杂度和阅读难度。此外,模板模式还可能导致类的层次结构变得更加复杂,需要进行仔细的设计。
总的来说,模板模式适用于需要实现一些具体算法,但是算法中的某些步骤可能存在差异,需要在子类中进行定制的情况。它可以让代码更加简洁,易于维护,同时提高代码的复用性和扩展性。