1.2.1设计模式(一)
背景
设计模式是什么?
- 是软件开发中,经过验证的,用于解决在特定环境下,重复出现的特定问题的解决方案
- 是解决问题的固定套路
- 慎用设计模式
设计模式是怎么来的?
通过满足设计原则之后,慢慢迭代出来的
设计模式解决了什么问题?
前提:具体的需求既有稳定点,又有变化点
期望修改少量代码就可以适应需求的变化
比喻:整洁的房间,好动的猫,怎么保证房间的整洁?把猫放在笼子里
设计模式基础
1)面向对象的思想
- 封装 -------- 隐藏实现细节,实现模块化
- 继承 -------- 无需改变原有类的情况下通过继承实现对功能的扩展
- 多态 -------- 静态多态(函数重载),动态多态(虚函数重写)
2)设计原则
- 依赖倒置原则
- 高层模块不应该依赖低层模块,两者都应该依赖于抽象
- 抽象不应该依赖具体实现,具体实现应该依赖于抽象
- 例子:自动驾驶公司是高层,汽车生产商是低层,他们不应该互相依赖。一方变动,另一方也会跟着变动;而应该抽象一个自动驾驶行业标准,高层和低层都依赖它;这样就解耦了两方的变动;自动驾驶系统,汽车生产商都是具体实现,他们应该都依赖自动驾驶行业标准(抽象);
- 开放封闭原则
- 对扩展开放,对修改关闭
- 类、模块、函数,可以去扩展,但不要去修改。如果要修改代码,尽量用继承或组合的方式来扩展类的功能,而不是直接修改类的代码。
- 单一职责原则
- 一个类应该只有一个发生变化的原因,即一个类只负责一项任务或功能。
- 最少知识原则
- 尽量减少对象之间的交互,从而减小类之间的耦合。在做系统设计时,不要让一个类依赖于太多其他的类,需尽量减小依赖关系
- 接口隔离原则
- 客户端不应该依赖于它不使用的接口。应该将大的接口拆分成小的、特定的接口。
- 里式替换原则
- 子类对象必须能够替换掉它们的父类对象,而不影响程序的行为。
23种设计模式(一)
模板方法模式(Template Method):
在方法中定义算法的骨架,延迟到子类中实现
稳定点:算法的骨架(流程,步骤)
变化点:重写某些具体的步骤
例子:某品牌动物园,有一套固定的表演流程,但是其中若干个表演可以创新替换,以尝试迭代更新表演流程
原流程:猴子->老虎->狗熊->山羊
替换为:猴子->大象->长颈鹿->山羊
代码实现:
不使用设计模式:
#include <iostream>
using namespace std;
// 定义每个动物的表演函数
void monkeyShow() {
cout << "猴子表演" << endl;
}
void tigerShow() {
cout << "老虎表演" << endl;
}
void bearShow() {
cout << "狗熊表演" << endl;
}
void goatShow() {
cout << "山羊表演" << endl;
}
void elephantShow() {
cout << "大象表演" << endl;
}
void giraffeShow() {
cout << "长颈鹿表演" << endl;
}
// 定义一个函数来执行原始流程
void originalProcess() {
monkeyShow();
tigerShow();
bearShow();
goatShow();
}
// 定义一个函数来执行替换后的流程
void replacedProcess() {
monkeyShow();
elephantShow();
giraffeShow();
goatShow();
}
int main() {
// 执行原始流程
cout << "执行原始流程:" << endl;
originalProcess();
// 执行替换后的流程
cout << "\n执行替换后的流程:" << endl;
replacedProcess();
return 0;
}
使用模板方法模式改进后
// 抽象类,定义算法的骨架
class AnimalAction {
public:
// 模板方法,定义算法的框架
virtual void performActions() {
step1();
step2();
step3();
step4();
}
protected:
// 抽象方法,由子类实现具体的行为
virtual void step1() = 0;
virtual void step2() = 0;
virtual void step3() = 0;
virtual void step4() = 0;
};
然后,我们为每套流程定义一个具体的类,这些类继承自AnimalAction类,并实现具体的步骤:
// 第一套
class Action1 : public AnimalAction {
protected:
void step1() override {
std::cout << "猴子表演" << std::endl;
}
void step2() override {
std::cout << "老虎表演" << std::endl;
}
void step3() override {
std::cout << "狗熊表演" << std::endl;
}
void step4() override {
std::cout << "山羊表演" << std::endl;
}
};
// 第二套
class Action2 : public AnimalAction {
protected:
void step1() override {
std::cout << "猴子表演" << std::endl;
}
void step2() override {
std::cout << "大象表演" << std::endl;
}
void step3() override {
std::cout << "长颈鹿表演" << std::endl;
}
void step4() override {
std::cout << "山羊表演" << std::endl;
}
};
最后,我们可以使用这些类来执行不同的流程
int main() {
AnimalAction* action;
// 使用猴子->老虎->狗熊->山羊的流程
action = new MonkeyAction();
action->performActions();
delete action;
// 使用猴子->大象->长颈鹿->山羊的流程
action = new ElephantAction();
action->performActions();
delete action;
return 0;
}
观察者模式(Observer):
对象间的一对多依赖关系,当一个对象改变状态时,所有依赖于它的对象都会得到通知并自动更新。
稳定点:一对多的依赖关系,“一”变化的时候“多”跟着变化
变化点:“多”增加,“多”减少
例子:某气象站发布气象资料给数据中心,数据中心经过处理,将气象站的信息更新到两个不同的终端( A和B);
#include <iostream>
#include <vector>
#include <algorithm>
class Observer {
public:
virtual ~Observer() {}
virtual void update() = 0; // 纯虚函数,具体的更新操作由子类实现
};
class Subject {
private:
std::vector<Observer*> observers; // 观察者列表
public:
virtual ~Subject() {}
// 注册观察者
void attach(Observer* observer) {
observers.push_back(observer);
}
// 注销观察者
void detach(Observer* observer) {
observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
}
// 通知所有观察者
void notify() {
for (Observer* observer : observers) {
observer->update();
}
}
};
接下来,我们创建两个具体的观察者类ConcreteObserverA和ConcreteObserverB:
由于继承自Observer类所以要重写Obsever类中的update()虚函数
class ConcreteObserverA : public Observer {
public:
void update() override {
std::cout << "ConcreteObserverA: Reacting to the event" << std::endl;
}
};
class ConcreteObserverB : public Observer {
public:
void update() override {
std::cout << "ConcreteObserverB: Reacting to the event" << std::endl;
}
};
然后,我们可以创建一个具体的Subject类ConcreteSubject,它将使用观察者模式:
class ConcreteSubject : public Subject {
private:
std::string state; // 主题的当前状态
public:
void setState(const std::string& newState) {
state = newState;
notify(); // 状态改变时通知所有观察者
}
std::string getState() const {
return state;
}
};
最后,在main函数中,我们将创建ConcreteSubject和观察者对象,注册观察者,改变状态,并观察结果:
int main() {
//创建一个项目(被观察的对象)
ConcreteSubject subject;
//创建两个观察者
ConcreteObserverA observerA;
ConcreteObserverB observerB;
//把观察者加入要观察的项目的项目队列中
subject.attach(&observerA);
subject.attach(&observerB);
// 改变状态,观察者将被通知
subject.setState("State 1");
subject.setState("State 2");
// 注销一个观察者
subject.detach(&observerA);
// 再次改变状态,只有未注销的观察者会被通知
subject.setState("State 3");
return 0;
}
策略模式(Strategy)
定义一系列算法,把它们一个个封装起来,并使它们可互换。
稳定点:客户程序与算法的调用关系
变化点:可互换
例子:某商场节假日有固定的促销活动,为了加大促销力度,现提升国庆节促销活动规格;
代码:
首先,定义一个Strategy接口,所有的促销策略都将实现这个接口:
class Strategy {
public:
virtual ~Strategy() {}
virtual void Promotion() const = 0;
// 纯虚函数,具体的促销逻辑由子类实现
};
然后,实现不同的促销策略:
// 普通节假日促销策略A, 要实现父类虚函数Promotion()
class StrategyA : public Strategy {
public:
void Promotion() const override {
std::cout << "Applying regular holiday promotion(A)." << std::endl;
}
};
// 国庆节促销策略B, 要实现父类虚函数Promotion()
class StrategyB : public Strategy {
public:
void Promotion() const override {
std::cout << "Applying enhanced National Day promotion(B)." << std::endl;
}
};
接下来,定义一个Mall类,它将使用一个Strategy对象来执行促销活动:
class Mall {
private:
//成员变量,一个接口类
Strategy* promotionStrategy;
public:
//有参构造
Mall(Strategy* strategy) : promotionStrategy(strategy) {}
// 执行促销活动
void runPromotion() const {
//promotionStrategy是Strategy类的成员变量
//Promotion()是Strategy类的成员函数
promotionStrategy->Promotion();
}
// 改变促销策略
void changePromotionStrategy(Strategy* newStrategy) {
delete promotionStrategy; // 释放旧策略
promotionStrategy = newStrategy; // 采用新策略
}
~Mall() {
delete promotionStrategy; // 销毁策略
}
};
最后,在main函数中,创建商场实例和不同的促销策略,然后根据需要改变促销策略:
int main() {
// 创建商场,初始使用普通节假日促销策略
Mall mall(new StrategyA());
mall.runPromotion(); // 运行普通节假日促销活动
// 国庆节来临,提升促销活动规格
Mall* nationalDayMall = new Mall(new StrategyB());
nationalDayMall->runPromotion(); // 运行国庆节促销活动
// 假设国庆节结束后,恢复普通促销活动
nationalDayMall->changePromotionStrategy(new StrategyB());
nationalDayMall->runPromotion(); // 运行普通节假日促销活动
delete nationalDayMall; // 清理资源
return 0;
}