• 设计模式(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,下面再举一个例子说明一下吧。

    作者:张锋
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。
    更多精彩文章可以观注
    微信公众号 soft张三丰

    微信交流群,添加群主微信,邀请入群
  • 相关阅读:
    javascript cookie
    mark几个比较好的配色网站
    Javascrip 淡入淡出思路
    实验报告:统计字符串中子字符串出现的次数
    Javascript计算器
    《node入门》学习
    配置ionic(低版本)
    eclipse环境配置
    关于文档加载的方法
    javascript基础-《web前端最佳实践》
  • 原文地址:https://www.cnblogs.com/skyme/p/2008966.html
Copyright © 2020-2023  润新知