设计模式(2)-策略模式之多用组合少用继承
首先看一下策略模式的意图
定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
结构
适用性
许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。
需要使用一个算法的不同变体。例如,你可能会定义一些反映不同的空间/时间权衡的算法。当这些变体实现为一个算法的类层次时[ H O 8 7 ] ,可以使用策略模式。
算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。
一个类定义了多种行为, 并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的S t r a t e g y 类中以代替这些条件语句。
这样看起来非常抽象,结合上个例子,修改一下程序的结构,根据策略模式。
类图如下
修改后程序如下,添加Context.h,Context.cpp,修改main
Context.h
class Context { private : Operaton* operaton; public : Context(); Context(Operaton* oper); virtual ~Context(); virtual int getResult(); }; |
Context.cpp
#include "stdafx.h" #include "Operaton.h" #include "Context.h" Context::Context(){ } Context::Context(Operaton* oper){ operaton = oper; } Context::~Context(){ } int Context::getResult(){ return operaton->getResult(); } |
main
#include "stdafx.h" #include <string> #include <iostream> #include "Operaton.h" #include "OperatonAdd.h" #include "OperatonDiv.h" #include "OperatonMul.h" #include "OperatonSub.h" #include "Context.h" using namespace std; int main( int argc, char * argv[]) { int strNumA,strNumB; int strOperator; cout<< "请输入数字A:\n" ; cin>>strNumA; cout<< "请选择运算符号(1,+,2,-,3,*,4,/):\n" ; cin>>strOperator; cout<< "请输入数字B:\n" ; cin>>strNumB; int strResult = 0; Operaton *op; Context *context; switch (strOperator) { case OPERATOR_ADD: op = new OperatonAdd(); break ; case OPERATOR_MINUS: op = new OperatonSub(); break ; case OPERATOR_MUTHL: op = new OperatonMul(); break ; case OPERATOR_DIV: op = new OperatonDiv(); break ; default : cout<< "输入有错误!" <<endl; break ; } op->numA = strNumA; op->numB = strNumB; context = new Context(op); strResult = context->getResult(); cout<< "得到的结果是:" <<strResult; return 0; } |
现在有个问题,switch又跑到客户端来处理了。
结合简单工厂优化一下代码吧!
修改后的程序如下
Context.h
#include "Operaton.h" #include "OperatonAdd.h" #include "OperatonDiv.h" #include "OperatonMul.h" #include "OperatonSub.h" class Context { private : Operaton *op; public : Context(); Context( int strOperator); virtual ~Context(); virtual int getResult( int numA, int numB); }; |
Context.cpp
#include "stdafx.h" #include "Context.h" Context::Context(){ } Context::Context( int strOperator){ switch (strOperator) { case OPERATOR_ADD: op = new OperatonAdd(); break ; case OPERATOR_MINUS: op = new OperatonSub(); break ; case OPERATOR_MUTHL: op = new OperatonMul(); break ; case OPERATOR_DIV: op = new OperatonDiv(); break ; default : cout<< "输入有错误!" <<endl; break ; } } Context::~Context(){ } int Context::getResult( int numA, int numB){ return op->getResult(numA,numB); } |
main
#include "stdafx.h" #include <string> #include <iostream> #include "Context.h" using namespace std; int main( int argc, char * argv[]) { int strNumA,strNumB; int strOperator; cout<< "请输入数字A:\n" ; cin>>strNumA; cout<< "请选择运算符号(1,+,2,-,3,*,4,/):\n" ; cin>>strOperator; cout<< "请输入数字B:\n" ; cin>>strNumB; int strResult = 0; Context *context; context = new Context(strOperator); strResult = context->getResult(strNumA,strNumB); cout<< "得到的结果是:" <<strResult; return 0; } |
修改后,客户端的代码已经和原来一样了,还有一个很重要的一点,客户端现在只要处理一个Context对象就可以了,减少了代码之间的耦合。
策略模式封装了变化。
采用策略模式的好处主要有以下几点:
1.提供了管理相关的算法族的办法。
2.提供了可以替换继承关系的办法。
3.避免使用多重条件转移语句
但是它也自身的缺点:
1.客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
2.造成很多的策略类。
对于这种处理,可以将原来混在一起的继承有效的分离出来,将原来各种处理放到一个类中,即Context,下面再举一个例子说明一下吧。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架