设计模式(2)-策略模式之多用组合少用继承

简介: 首先看一下策略模式的意图 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。 结构   适用性 许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。

首先看一下策略模式的意图

定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

结构

 img_c4772aa1f82d9bd3372a34e1f196c698.jpg

适用性

许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。
需要使用一个算法的不同变体。例如,你可能会定义一些反映不同的空间/时间权衡的算法。当这些变体实现为一个算法的类层次时[ H O 8 7 ] ,可以使用策略模式。
算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与算法相关的数据结构。
一个类定义了多种行为, 并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的S t r a t e g y 类中以代替这些条件语句。

这样看起来非常抽象,结合上个例子,修改一下程序的结构,根据策略模式。

类图如下

img_fcc34253c5b3e994dfd0ee886c6e2de3.jpg

修改后程序如下,添加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,下面再举一个例子说明一下吧。

目录
相关文章
|
8月前
|
设计模式
二十三种设计模式全面解析-装饰器模式-超越继承的灵活装扮
二十三种设计模式全面解析-装饰器模式-超越继承的灵活装扮
|
7月前
|
设计模式 Java 数据库
Java设计模式:桥接模式实现灵活组合,超越单一继承的设计之道(十)
Java设计模式:桥接模式实现灵活组合,超越单一继承的设计之道(十)
|
8月前
|
设计模式 缓存 安全
探索设计模式的魅力:从单一继承到组合模式-软件设计的演变与未来
组合模式:构建灵活树形结构的艺术。 组合模式旨在解决如何将对象组合成树形结构,隐藏具体实现,使客户端对单个对象和复合对象的使用具有一致性。通过将对象组合成树形结构,组合模式提供了层次化的结构,使系统更灵活、可扩展。 核心思想在于统一叶节点和组合节点。叶节点代表具体的对象,而组合节点则是其他对象的容器。该设计允许我们以统一的方式处理叶子和组合,简化了许多操作。实践中,组合模式适用于具有树形结构并且希望保持结构灵活的系统。它不仅提高了代码的可重用性和可维护性,还使得添加新功能变得简单,无需修改现有代码。...
100 0
|
设计模式
设计模式小例子理解封装、继承、多态
设计模式小例子理解封装、继承、多态
93 0
|
设计模式 JSON 前端开发
前端面试必看(手写Promise+js设计模式+继承+函数柯里化等)JavaScript面试全通关(1/3)
前端面试必看(手写Promise+js设计模式+继承+函数柯里化等)JavaScript面试全通关(1/3)
79 0
|
设计模式 JavaScript 前端开发
JavaScript设计模式(一):面向对象编程 - 继承
/ 利用闭包实现 let Book =(function() {// 静态私有变量 let bookNum = 0;// 静态私有方法 let checkBook = function(name) {};// 创建类 function _book(newId , newName , newPrice) {// 私有变量 let name , price;// 私有方法 function checkID(id) {} // 特权方法 this . getName =() => name;
187 1
|
设计模式 Java
【Java设计模式 面向对象设计思想】五 多用组合少用继承编程
【Java设计模式 面向对象设计思想】五 多用组合少用继承编程
251 0
【Java设计模式 面向对象设计思想】五 多用组合少用继承编程
|
设计模式 程序员 编译器
【大话设计模式】封装 继承 多态
【大话设计模式】封装 继承 多态
|
设计模式 存储 安全
【Java设计模式 面向对象设计思想】一 再谈面向对象和封装、抽象、继承、多态四大特性
【Java设计模式 面向对象设计思想】一 再谈面向对象和封装、抽象、继承、多态四大特性
99 0
|
设计模式 JavaScript
“工厂、构造、原型” 设计模式与 JS 继承
“工厂、构造、原型” 设计模式与 JS 继承