• 不一样的策略模式(设计模式五)


    前言

    什么是设计模式?说白了就是套路,是经过历代程序员总结出来的。很多时候我们虽然学会了很多套路,但是啥时候使用,使用哪个合适,我想这才是问题的关键。
    知道怎么用不知道什么时候用,这时候看下代码风格也行用的上,策略模式是非常容易通过代码风格使用上的。
    策略模式,为什么叫策略模式呢?其实策略模式还有一个别名叫做政策(policy)模式,在古代,对不同的国家呢,实行不同的政策,对A呢,采取税务10%,对B国采取税务20%。
    这样根据不同国家政策不同呢,在计算机中就是根据不同对象采取不同的方法,就叫做策略模式咯。但是呢,如果直接采用if else 这种行为呢,人们发现过于臃肿,且复用性极差,那么就形成了这样一种模式去缓解这个问题。
    策略模式属于对象行为模式,其实不去看概念也很好记,在运行时针对不同对象,去做出相应的行为。至于为什么不分到结构型或者其他型,只是它更符合行为型,一个类的行为或其算法可以在运行时更改,这些分类其实没有绝对的界限,只是有权威人士对其进行了规划。
    那么策略模式的风格是什么,查看正文。

    开车出发

    public enum PolicyBase
    {
    	US_Policy,
    	DE_Policy,
    	FR_Policy
    }
    public class Strategy
    {
    	PolicyBase policyBase;
    
    	public Strategy(PolicyBase policyBase) {
    		this.policyBase = policyBase;
    	}
    	public double CalculatePolicy() {
    		if (policyBase == PolicyBase.US_Policy)
    		{
    			return 0.9;
    		}
    		else if (policyBase == PolicyBase.DE_Policy)
    		{
    			return 0.8;
    		}
    		else if (policyBase == PolicyBase.FR_Policy)
    		{
    			return 0.1;
    		}
    		return 0;
    	}
    }
    

    根据不同的国家,采取了不同的政策。这样一看好像没有啥问题啊,根据了不同国家制定了不同税法。
    但是呢,在开发代码的时间轴上,也就是未来的角度上存在的极大的问题。比如和英国(GB)合作了,我得改吧?然后又和另外一个国家合作了,恐怕又得来一遍。
    这时候有人就纳闷了,还想不改代码?代码的确是要改的,但是不能违法了封闭开发原则。


    在红色部分呢,是我们需要继续往下添加代码的地方,也就是我们加一个国家就需要把我们写过的任何一个区域改一遍。
    我想这就很糟糕了,牵扯太大,对于发布来说就需要测试整个子模块,我想这代价无法让人接受,这时候策略者模式就出现了。

    public enum PolicyBase
    {
    	US_Policy,
    	DE_Policy,
    	FR_Policy
    }
    public interface Policy
    {
    	double Calculate();
    }
    
    public class USPolicy : Policy
    {
    	public double Calculate()
    	{
    		throw new NotImplementedException();
    	}
    }
    
    public class DEPolicy : Policy
    {
    	public double Calculate()
    	{
    		throw new NotImplementedException();
    	}
    }
    
    public class FRPolicy : Policy
    {
    	public double Calculate()
    	{
    		throw new NotImplementedException();
    	}
    }
    
    public class StrategyFactory{
    	Policy policy;
    	public StrategyFactory(PolicyBase policyBase) {
    		switch (policyBase)
    		{
    			case PolicyBase.US_Policy:
    				policy = new USPolicy();
    				break;
    			case PolicyBase.DE_Policy:
    				policy = new DEPolicy();
    				break;
    			case PolicyBase.FR_Policy:
    				policy = new FRPolicy();
    				break;
    		}
    	}
    	public Policy GetPolicy() {
    		return policy;
    	}
    }
    
    class SalesOrder
    {
    	private Policy Policy;
    
    	public SalesOrder(StrategyFactory strategyFactory)
    	{
    		this.Policy = strategyFactory.GetPolicy();
    	}
    
    	public double CalculatePolicy()
    	{
    		double val = Policy.Calculate();
    		return val;
    	}
    
    };
    

    上述代码中,通过策略者模式把原来的获取各国的税法比例变成了SalesOrder类,而这个类不再改变,也就是说所以依赖于获取各国税法参数的将依赖于一个稳定的类。
    这时候很多纳闷了,如果我需要添加一个英国(GB),依然需要在红色部分就行修改啊,修改的地方如下:


    修改的地方一样多,且还要多加一个GBPolicy类,这不是白忙活了吗?
    首先我们来看下前后依赖关系图:
    使用策略模式前:

    使用策略模式后:

    这样一看,不仅是没有啥好处,还复杂了。
    然而这样一想,我们处理的是解决这个税法问题这个业务上,可以肯定的就是使用策略模式后,我下面红框部分稳定了,也就是在二进制上可以复用,但是上面红色部分倒是有问题了,耦合太大。
    但是呢,我们知道上面复杂部分其实就是简单工厂模式,问题就回到了如何优化简单工厂模式了,如果能解决上面红框的问题,那么是可行的。
    由于篇幅有限,下一篇总结工厂模式到抽象工厂到反射这个演化。
    这时候我们看到了,如果遇到了if else 且以后会增加else if,可以用策略模式,去缓解这个问题,增加代码复用性。
    但是稳定的if else 呢是不需要的,比如说星期一到星期日,这种就是稳定的了,本来处于稳定的,那么其改变的价值就不是很大。

    uml图

    后续补上

    总结

    策略模式的作用,解决使用不稳定 的if...else 所带来的复杂和难以维护。

  • 相关阅读:
    Codeforces 526D Om Nom and Necklace (KMP)
    HDU
    HDU
    Codeforces 219D
    HDU
    HDU
    POJ
    HDU
    HDU
    第二次作业
  • 原文地址:https://www.cnblogs.com/aoximin/p/12090000.html
Copyright © 2020-2023  润新知