重构没有固定的形式,多年来我使用过不同的版本,并且我敢打赌不同的人也会有不同的版本。 该重构适用于这样的场景:switch语句块很大,并且会随时引入新的判断条件。这时,最好使用策略模式将每个条件封装到单独的类中。实现策略模式的方式是很多的。我在这里介绍的策略重构使用的是字典策略,这么做的好处是调用者不必修改原来的代码。

public class ClientCode {
public double CalculateShipping() {
ShippingInfo shippingInfo = new ShippingInfo();
return shippingInfo.CalculateShippingAmount(State.Alaska);
}
}
public enum State {
Alaska, NewYork, Florida
}
public class ShippingInfo {
public double CalculateShippingAmount(State shipToState) {
switch (shipToState) {
case State.Alaska:
return GetAlaskaShippingAmount();
case State.NewYork:
return GetNewYorkShippingAmount();
case State.Florida:
return GetFloridaShippingAmount();
default:
return 0d;
}
} private double GetAlaskaShippingAmount() {
return 15d;
}
private double GetNewYorkShippingAmount() {
return 10d;
}
private double GetFloridaShippingAmount() {
return 3d;
}
}
要应用该重构,需将每个测试条件至于单独的类中,这些类实现了一个共同的接口。然后将枚举作为字典的键,这样就可以获取正确的实现,并执行其代码了。以后如果希望添加新的条件,只需添加新的实现类,并将其添加至ShippingCalculations字典中。正如前面说过的,这不是实现策略模式的唯一方式。我在这里将字体加粗显示,是因为肯定会有人在评论里指出这点:)用你觉得好用的方法。我用这种方式实现重构的好处是,不用修改客户端代码。所有的修改都在ShippingInfo类内部。 
Jayme Davis指出这种重构由于仍然需要在构造函数中进行绑定,所以只不过是增加了一些类而已,但如果绑定IShippingCalculation的策略可以置于IoC中,带来的好处还是很多的,它可以使你更灵活地捆绑策略
public class ClientTest {
public Double CalculateShipping() {
ShippingInfo shippingInfo = new ShippingInfo();
return shippingInfo.CalculateShippingAmount(State.Alaska);
}
}
public enum State {
Alaska, NewYork, Florida
}
public class ShippingInfo {
private Dictionary<State, IShippingCalculation> ShippingCalculations; public ShippingInfo() {
ShippingCalculations =new Hashtable<State, IShippingCalculation>();
ShippingCalculations.put(State.Alaska, new AlaskShippingCalculation());
ShippingCalculations.put(State.NewYork, new NewYorkShippingCalculation());
ShippingCalculations.put(State.Florida, new FloridaShippingCalculation());
} public Double CalculateShippingAmount(State shipToState) {
return ShippingCalculations.get(shipToState).Calculate();
}
}
public interface IShippingCalculation {
Double Calculate();
}
public class AlaskShippingCalculation implements IShippingCalculation {
public Double Calculate () {
return 15d;
}
}
public class NewYorkShippingCalculation implements IShippingCalculation {
public Double Calculate () {
return 10d;
}
}
public class FloridaShippingCalculation implements IShippingCalculation {
public Double Calculate () {
return 3d;
}
}
为了使这个示例圆满,我们来看看在ShippingInfo构造函数中使用Ninject为IoC容器时如何进行绑定。需要更改的地方很多,主要是将state的枚举放在策略内部,以及Ninject向构造函数传递一个IShippingInfo的IEnumerable泛型。接下来我们使用策略类中的state属性创建字典,其余部分保持不变。(感谢Nate Kohari和Jayme Davis)
public interface IShippingInfo {
Double CalculateShippingAmount(State state);
} public class ClientCode {
public IShippingInfo ShippingInfo;
public Double CalculateShipping() {
return ShippingInfo.CalculateShippingAmount(State.Alaska);
}
}
public enum State{
Alaska, NewYork, Florida;
} public class ShippingInfo implements IShippingInfo{
private Dictionary<State, IShippingCalculation> ShippingCalculations=new Hashtable<State, IShippingCalculation>();
public ShippingInfo(IShippingCalculation<State> shippingCalculations) {
for(State state:State.values()) {
ShippingCalculations.put(state, shippingCalculations);
}
}
public Double CalculateShippingAmount(State shipToState) {
return ShippingCalculations.get(shipToState).Calculate();
}
} public interface IShippingCalculation<State> {
State getState();
Double Calculate();
} public class AlaskShippingCalculation implements IShippingCalculation {
@Override
public State getState() {
return State.Alaska;
}
@Override
public Double Calculate() {
return 15d;
}
} public class NewYorkShippingCalculation implements IShippingCalculation {
@Override
public State getState() {
return State.NewYork;
}
@Override
public Double Calculate() {
return 10d;
}
} public class FloridaShippingCalculation implements IShippingCalculation {
@Override
public State getState() {
return State.Florida;
}
@Override
public Double Calculate() {
return 3d;
}
}
 
 
 

重构11-Switch to Strategy(Switch到策略模式)的更多相关文章

  1. 1.Strategy Pattern(策略模式)

    策略模式(Strategy Pattern): 我的理解,将代码中每个变化之处抽出,提炼成一个一个的接口或者抽象类,让这些变化实现接口或继承抽象类成为具体的变化类.再利用多态的功能,可将变化之处用接口 ...

  2. Strategy Pattern(策略模式)

    Head First定义: 策略模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户. 策略模式的设计原则主要有三个: 找出应用中可能需要变化的部分,把它们独 ...

  3. 使用策略模式重构switch case 代码

    目录 1.背景 2.案例 3.switch…case…方式实现 4.switch…case…带来的问题 5.使用策略模式重构switch…case…代码 6.总结 1.背景 之前在看<重构    ...

  4. 使用反射+策略模式代替项目中大量的switch case判断

    我这里的业务场景是根据消息类型将离线消息存入mongoDB不同的collection中.其中就涉及到大量的分支判断,为了增强代码的可读性和可维护性,对之前的代码进行了重构. 先对比一下使用反射+策略模 ...

  5. C#设计模式系列:策略模式(Strategy)

    1.策略模式简介 1.1>.定义 策略是为达到某一目的而采取的手段或方法,策略模式的本质是目标与手段的分离,手段不同而最终达成的目标一致.客户只关心目标而不在意具体的实现方法,实现方法要根据具体 ...

  6. 设计模式笔记:策略模式(Strategy)

    1. 策略模式简介 1.1 定义 策略是为达到某一目的而采取的手段或方法,策略模式的本质是目标与手段的分离,手段不同而最终达成的目标一致.客户只关心目标而不在意具体的实现方法,实现方法要根据具体的环境 ...

  7. 第21章 策略模式(Strategy Pattern)

    原文 第21章 策略模式(Strategy Pattern) 策略模式 导读:策略模式看完之后,大多数人都会感觉有点混了,包括我,感觉策略模式是一种OO思想的体现(纯属个人拙见). 概述:       ...

  8. 反馈法学习设计模式(一)——策略模式Strategy Pattern

    简介(Introduction) 之前学习Java8实战时,遇到一个很好的策略模式示例.便想着借着这个示例结合反馈式的方法来,学习策略设计模式,也以便后面反复琢磨学习. 首先我们通过练习,逐步写出符合 ...

  9. 策略模式(Strategy)简介

    一.策略模式(Strategy)简介 策略模式是行为模式. 行为模式:规定了各个对象应该具备的职责以及对象间的通信模式,它很好的规范了对象间调用和数据传递方式 策略模式适合于算法经常变化的情况 算法的 ...

  10. Spring中常见的设计模式——策略模式

    策略模式(Strategy Pattern) 一.策略模式的应用场景 策略模式的应用场景如下: 系统中有很多类,而他们的区别仅仅在于行为不同. 一个系统需要动态的在集中算法中选择一种 二.用策略模式实 ...

随机推荐

  1. 汇编语言程序入门实验一:在dos下对用户输入作出应答

    汇编语言程序入门实验一:在dos下对用户输入作出应答 1,背景 成功预言了今天要上计算机操作系统上机实验课,昨天预习后,今天的两个上机实验做得很成功.但是也有一些问题.问题1:学校的系统目前是wind ...

  2. Animation Spinner【项目】

    https://github.com/vjpr/healthkick/blob/master/src/win/healthkick/ucSpinnerCogs.xaml 网上的例子,放在UserCon ...

  3. Flex应用程序如何启动

    Flex应用程序启动 编写一个简单的Flex应用程序并不复杂,就算你从来没接触过Flex程序设计,照着帮助的实例步骤,不需花多长时间也能做出一个漂亮简捷的小程序出来.不过,随着对Flex程序编写的深入 ...

  4. oracle中substr函数的用法

    1.substr(string string, int a, int b) 参数1:string 要处理的字符串 参数2:a 截取字符串的开始位置(起始位置是0) 参数3:b 截取的字符串的长度(而不 ...

  5. HRESULT 0x80131515 解决方法

    http://254698001.blog.51cto.com/2521548/1339696 很多朋友在加载DLL是发生这样的错误:HRESULT: 0x80131515. 解决方法是,在DLL文件 ...

  6. 使用 DLL 的优点

    动态链接具有下列优点: 节省内存和减少交换操作.很多进程可以同时使用一个 DLL,在内存中共享该 DLL 的一个副本.相反,对于每个用静态链接库生成的应用程序,Windows 必须在内存中加载库代码的 ...

  7. 关于java.lang.IllegalArgumentException: View not attached to window manager 错误的分析

    今天遇到一个很奇特的问题,当用户设置了PIN码,在锁屏界面正常解锁PIN码后,进入Launcher时显示com.android.phone 已停止运行.一开始猜想会不会是解锁PIN码的时候处理导致了P ...

  8. GLSL实现Image Filter 【转】

    http://blog.csdn.net/a3070173/archive/2008/11/27/3390477.aspx 图像过滤无论是在作图工具还是特效的实现上都时有运用,这里发一些通常会使用到的 ...

  9. Linux - wc统计文件行数、单词数或字节数

    一 wc简单介绍 wc命令用来打印文件的文本行数.单词数.字节数等(print the number of newlines, words, and bytes in files).在Windows的 ...

  10. sql server常用知识点

    --删除表 use [20130823_Recource] go drop table my_table1,my_table2,My_table3 --创建表 use [20130823_Recour ...