设计模式——策略模式
一、引言
十一黄金周,对于像我们这些屌丝来说,确实是个不错的出游时机,可惜的就是这个假期是public的,并不是我等屌丝独占的。真是有种生前活在人堆里的感慨,这时候选择交通工具是异常的重要,笔者回家需要经过深汕高速,每逢节假日,高速基本都会成为免费停车场的,加之国庆免费,真是雪上加霜啊。今天我所写的就是以选择交通工具为题阐述一下策略模式吧。
二、策略模式
1. 定义:定义一组算法,将每个算法都封装起来,并使他们之间可以互换。
2. 类图:【如下图所示】
3. 类图说明:
3.1 ITransport:策略抽象类,定义每个算法必须具有的方法和属性。
3.2 Plane,Train,Car:策略中一组算法。
3.3 Context:上下文角色,封装算法提供客户端调用的。
三、策略示例代码
1. 策略抽象类
package com.pattern.stratgy.core; /** * 策略接口——交通工具 * @author yemaoan * */ public interface ITransport { void buyTicket(); }
2. 具体策略(算法)
2.1 选择火车
package com.pattern.stratgy.core; public class Train implements ITransport { @Override public void buyTicket() { System.out.println("选择坐火车,硬座还比较划算"); } }
2.2 选择飞机
package com.pattern.stratgy.core; public class Plane implements ITransport { @Override public void buyTicket() { System.out.println("选择坐飞机吧,快速,便捷,关键啊,是不会塞车..."); } }
2.3 选择汽车
package com.pattern.stratgy.core; public class Car implements ITransport { @Override public void buyTicket() { System.out.println("选择坐汽车,堵就堵吧"); } }
3. Context封装角色
package com.pattern.stratgy.core; /** * 封装角色 * @author yemaoan * */ public class Context { private ITransport transport; public Context(ITransport transport) { this.transport = transport; } public void buyTicket() { this.transport.buyTicket(); } }
4. JunitTest
package com.pattern.strategy.test; import org.junit.Test; import com.pattern.stratgy.core.Context; import com.pattern.stratgy.core.ITransport; import com.pattern.stratgy.core.Train; public class TestStrategy { @Test public void testStrage() { //平生就差火车,动车没坐过了,让我也过一下火车瘾吧 ITransport transport = new Train(); //生成策略对象,这样Client就知道得太多了,不应该啊,这是病,得医~ Context context = new Context(transport); context.buyTicket(); } }
四、策略改进方法
其实单纯的策略模式的弊病已经在上面的代码中表现得很明显了,在客户端调用时已经把当前的策略暴露出去了,怎么解决?让工厂帮一下忙吧,让我们看一下下面的一段代码。
1. 策略工厂
package com.pattern.stategy.factory; import com.pattern.stratgy.core.ITransport; /** * 设计模式老朋友了——策略工厂类 * @author yemaoan * */ public class StrategyFactory { public static <T extends ITransport> T getTransport(Class<T> cls) { ITransport transport = null; try { transport = (ITransport) Class.forName(cls.getName()).newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return (T) transport; } public static <T extends ITransport> T getTransport(String code) { return (T) getTransport(new ContentService().get(code)); } }
2. 算法值映射类
package com.pattern.stategy.factory; import java.util.HashMap; import java.util.Map; import com.pattern.stratgy.core.Car; import com.pattern.stratgy.core.Plane; import com.pattern.stratgy.core.Train; /** * 算法映射 * @author yemaoan * */ public class ContentService { private Map<String, Class> contentMap = new HashMap<String, Class>(); public ContentService() { contentMap.put("train", Train.class); contentMap.put("plane", Plane.class); contentMap.put("car", Car.class); } public Class get(String key) { return contentMap.get(key); } }
3. JunitTest【Client】
package com.pattern.strategy.test; import org.junit.Test; import com.pattern.stategy.factory.StrategyFactory; import com.pattern.stratgy.core.Context; import com.pattern.stratgy.core.ITransport; import com.pattern.stratgy.core.Train; public class TestStrategy { @Test public void testStrage() { //平生就差火车,动车没坐过了,让我也过一下火车瘾吧 ITransport transport = new Train(); //生成策略对象,这样Client就知道得太多了,不应该啊,这是病,得医~ Context context = new Context(transport); context.buyTicket(); } @Test public void testStrategy() { ITransport transport = StrategyFactory.getTransport("train"); //让工厂模式帮了我一把 Context context = new Context(transport); context.buyTicket(); } }
五、总结
1. 本文是对策略模式的一个阐述,策略其实也算是一个比较好理解的模式吧。当然单纯的使用策略模式是不太现实的,因为它会把算法完全的暴露给调用者,兵家之大忌啊。
2. 针对策略模式的一些不足,笔者采用了工厂模式去解决,使得客户端调用时,只需要根据特定的code来获取相应的算法策略,而避免直接new算法策略。
出处: http://www.cnblogs.com/maoan/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。