第11天:用策略模式代替switch
今天的重构很有意思,旧的代码是根据参数State来调用三个不同的方法,获取三个地方的装运量
代码如下:
Code public class ClientCode { public decimal CalculateShipping() { ShippingInfo shippingInfo = new ShippingInfo(); return shippingInfo.CalculateShippingAmount(State.Alaska); } } public enum State { Alaska, NewYork, Florida } public class ShippingInfo { public decimal CalculateShippingAmount(State shipToState) { switch (shipToState) { case State.Alaska: return GetAlaskaShippingAmount(); case State.NewYork: return GetNewYorkShippingAmount(); case State.Florida: return GetFloridaShippingAmount(); default: return 0m; } } private decimal GetAlaskaShippingAmount() { return 15m; } private decimal GetNewYorkShippingAmount() { return 10m; } private decimal GetFloridaShippingAmount() { return 3m; } }
如果我们现在要加一个Chicago的条件,那么不得不修改整个ShippingInfo
重构后用策略模式,对每一个条件加一个类,并且实现同一个接口,以后如果希望添加新的条件,只需添加新的实现类就可以了,实现对修改关闭,对扩展开放
重构后的代码如下
Code public class ClientCode { public decimal CalculateShipping() { ShippingInfo shippingInfo = new ShippingInfo(); return shippingInfo.CalculateShippingAmount(State.Alaska); } } public enum State { Alaska, NewYork, Florida } public class ShippingInfo { private IDictionary<State, IShippingCalculation> ShippingCalculations { get; set; } public ShippingInfo() { ShippingCalculations = new Dictionary<State, IShippingCalculation>{ { State.Alaska, new AlaskShippingCalculation() }, { State.NewYork, new NewYorkShippingCalculation() }, { State.Florida, new FloridaShippingCalculation() }}; } public decimal CalculateShippingAmount(State shipToState) { return ShippingCalculations[shipToState].Calculate(); } } public interface IShippingCalculation { decimal Calculate(); } public class AlaskShippingCalculation : IShippingCalculation { public decimal Calculate() { return 15m; } } public class NewYorkShippingCalculation : IShippingCalculation { public decimal Calculate() { return 10m; } } public class FloridaShippingCalculation : IShippingCalculation { public decimal Calculate() { return 3m; } }
故事还没完,书的作者又进行了如下的重构,今天没有弄明白,先记录下来
Code public interface IShippingInfo { decimal CalculateShippingAmount(State state); } public class ClientCode { [Inject] public IShippingInfo ShippingInfo { get; set; } public decimal CalculateShipping() { return ShippingInfo.CalculateShippingAmount(State.Alaska); } } public enum State { Alaska, NewYork, Florida } public class ShippingInfo : IShippingInfo { private IDictionary<State, IShippingCalculation> ShippingCalculations { get; set; } public ShippingInfo(IEnumerable<IShippingCalculation> shippingCalculations) { ShippingCalculations = shippingCalculations.ToDictionary( calc => calc.State); } public decimal CalculateShippingAmount(State shipToState) { return ShippingCalculations[shipToState].Calculate(); } } public interface IShippingCalculation { State State { get; } decimal Calculate(); } public class AlaskShippingCalculation : IShippingCalculation { public State State { get { return State.Alaska; } } public decimal Calculate() { return 15m; } } public class NewYorkShippingCalculation : IShippingCalculation { public State State { get { return State.NewYork; } } public decimal Calculate() { return 10m; } } public class FloridaShippingCalculation : IShippingCalculation { public State State { get { return State.Florida; } } public decimal Calculate() { return 3m; } }