• 31天重构指南之十一:使用策略类


    今天要说的重构没有固定的来源, 在过去的几年里我使用了该重构的几个变体,我相信这个重构肯定还有其它的变体。

    这个重构一般适用的情形是当我们有许多的switch分支语句,并且经常由于有新的条件加入引起分支语句发生变化。在这种情形下我们经常引入策略模式并将每个分支条件语句定义成单独的策略类。这里我要展示的“使用策略类重构”是将上述情形重构成字典模式(策略模式的实现方式之一),这样做的好处是当您以后使用策略模式时类的使用者不需要做任何改变。

       1: namespace LosTechies.DaysOfRefactoring.SwitchToStrategy.Before
       2: {
       3:     public class ClientCode
       4:     {
       5:         public decimal CalculateShipping()
       6:         {
       7:             ShippingInfo shippingInfo = new ShippingInfo();
       8:             return shippingInfo.CalculateShippingAmount(State.Alaska);
       9:         }
      10:     }
      11:  
      12:     public enum State
      13:     {
      14:         Alaska,
      15:         NewYork,
      16:         Florida
      17:     }
      18:  
      19:     public class ShippingInfo
      20:     {
      21:         public decimal CalculateShippingAmount(State shipToState)
      22:         {
      23:             switch(shipToState)
      24:             {
      25:                 case State.Alaska:
      26:                     return GetAlaskaShippingAmount();
      27:                 case State.NewYork:
      28:                     return GetNewYorkShippingAmount();
      29:                 case State.Florida:
      30:                     return GetFloridaShippingAmount();
      31:                 default:
      32:                     return 0m;
      33:             }
      34:         }
      35:  
      36:         private decimal GetAlaskaShippingAmount()
      37:         {
      38:             return 15m;
      39:         }
      40:  
      41:         private decimal GetNewYorkShippingAmount()
      42:         {
      43:             return 10m;
      44:         }
      45:  
      46:         private decimal GetFloridaShippingAmount()
      47:         {
      48:             return 3m;
      49:         }
      50:     }
      51: }
     
    为了应用“使用策略类”重构,我们将条件提取到继承自同一个接口的单独类中,然后将enum作为key参数传入。如果以后我们想添加另一个条件,我们只需要添加一个实现自接口的条件类,
    并将它加入到ShippingCalculations字典中,如我之前提到的,这并不是实现策略模式的惟一方式,这样做的好处是当条件改变时ShippingInfo类的使用者不需要做任何改变,所有的改变
    都仅仅发生了ShippingInfo 类内部。
    Jayme Davis 指出由于绑定是通过构造函数(ctor)进行的,所以这个重构会产生更多的类,这是对的,但如果你可以应用IOC来实现IShippingCalculation模式的绑定会受益更多,这会使
    你应用策略模式更简单。
       1: using System.Collections.Generic;
       2:  
       3: namespace LosTechies.DaysOfRefactoring.SwitchToStrategy.After
       4: {
       5:     public class ClientCode
       6:     {
       7:         public decimal CalculateShipping()
       8:         {
       9:             ShippingInfo shippingInfo = new ShippingInfo();
      10:             return shippingInfo.CalculateShippingAmount(State.Alaska);
      11:         }
      12:     }
      13:  
      14:     public enum State
      15:     {
      16:         Alaska,
      17:         NewYork,
      18:         Florida
      19:     }
      20:  
      21:     public class ShippingInfo
      22:     {
      23:         private IDictionary<State, IShippingCalculation> ShippingCalculations { get; set; }
      24:  
      25:         public ShippingInfo()
      26:         {
      27:             ShippingCalculations = new Dictionary<State, IShippingCalculation>
      28:             {
      29:                 { State.Alaska, new AlaskShippingCalculation() },
      30:                 { State.NewYork, new NewYorkShippingCalculation() },
      31:                 { State.Florida, new FloridaShippingCalculation() }
      32:             };
      33:         }
      34:  
      35:         public decimal CalculateShippingAmount(State shipToState)
      36:         {
      37:             return ShippingCalculations[shipToState].Calculate();
      38:         }
      39:     }
      40:  
      41:     public interface IShippingCalculation
      42:     {
      43:         decimal Calculate();
      44:     }
      45:  
      46:     public class AlaskShippingCalculation : IShippingCalculation
      47:     {
      48:         public decimal Calculate()
      49:         {
      50:             return 15m;
      51:         }
      52:     }
      53:  
      54:     public class NewYorkShippingCalculation : IShippingCalculation
      55:     {
      56:         public decimal Calculate()
      57:         {
      58:             return 10m;
      59:         }
      60:     }
      61:  
      62:     public class FloridaShippingCalculation : IShippingCalculation
      63:     {
      64:         public decimal Calculate()
      65:         {
      66:             return 3m;
      67:         }
      68:     }
      69: }
     
    下面是一个当用Ninject来作为IOC容器时如何实现该重构的例子:
       1: public interface IShippingInfo
       2: {
       3:     decimal CalculateShippingAmount(State state);
       4: }
       5:  
       6: public class ClientCode
       7: {
       8:     [Inject]
       9:     public IShippingInfo ShippingInfo { get; set; }
      10:  
      11:     public decimal CalculateShipping()
      12:     {
      13:         return ShippingInfo.CalculateShippingAmount(State.Alaska);
      14:     }
      15: }
      16:  
      17: public enum State
      18: {
      19:     Alaska,
      20:     NewYork,
      21:     Florida
      22: }
      23:  
      24: public class ShippingInfo : IShippingInfo
      25: {
      26:     private IDictionary<State, IShippingCalculation> ShippingCalculations { get; set; }
      27:  
      28:     public ShippingInfo(IEnumerable<IShippingCalculation> shippingCalculations)
      29:     {
      30:         ShippingCalculations = shippingCalculations.ToDictionary(calc => calc.State);
      31:     }
      32:  
      33:     public decimal CalculateShippingAmount(State shipToState)
      34:     {
      35:         return ShippingCalculations[shipToState].Calculate();
      36:     }
      37: }
      38:  
      39: public interface IShippingCalculation
      40: {
      41:     State State { get; }
      42:     decimal Calculate();
      43: }
      44:  
      45: public class AlaskShippingCalculation : IShippingCalculation
      46: {
      47:     public State State { get { return State.Alaska; } }
      48:  
      49:     public decimal Calculate()
      50:     {
      51:         return 15m;
      52:     }
      53: }
      54:  
      55: public class NewYorkShippingCalculation : IShippingCalculation
      56: {
      57:     public State State { get { return State.NewYork; } }
      58:  
      59:     public decimal Calculate()
      60:     {
      61:         return 10m;
      62:     }
      63: }
      64:  
      65: public class FloridaShippingCalculation : IShippingCalculation
      66: {
      67:     public State State { get { return State.Florida; } }
      68:  
      69:     public decimal Calculate()
      70:     {
      71:         return 3m;
      72:     }
      73: }
    原文链接:http://www.lostechies.com/blogs/sean_chambers/archive/2009/08/11/refactoring-day-11-switch-to-strategy.aspx
  • 相关阅读:
    wampserver服务器离线,无法访问此网站 找不到 项目 的服务器 DNS 地址。
    node.js(一)介绍与安装
    js全局函數
    类和对象的定义
    iframe框架学习
    while和do-while的区别
    html5视频音频
    列表
    html表格的学习
    云课堂数组1
  • 原文地址:https://www.cnblogs.com/zhangronghua/p/1576409.html
Copyright © 2020-2023  润新知