几分钟带你搞懂策略模式

深渊向深渊呼唤
几分钟带你搞懂策略模式 几分钟带你搞懂观察者模式

小张:周五xx公园团建,安排见下,望周知:

    9:00 集合 9:00-11:00 登山 11:00-13:00 山顶集合,午餐

领导:小张啊,你规划几条上山路线,扔到群里。
小张自己查去,收到。
(十分钟后,微信群…)
小张:时间较紧,大家请自行合理安排上山路线

上山路程最短,较陡,xx->xx 适合拍照,景色美,xx->xx 山路好走,xx->xx

策略模式

关于策略模式的定义,我就直接引用HeadFirst书中的描述了:策略模式定义了算法蔟,并分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。类图见下:
在这里插入图片描述
我们用代码语言来描述下,为什么要使用接口,而不是直接使用具体的路线类?因为我们不应该把每个员工与具体的上山路线绑在一起,员工在登山时有权利改变路线(动态绑定),而当员工持有一个抽象上山路线类时,我们就可以在运行时动态的引用正确的具体上山路线类型(多态思想),所以我们应该针对接口编程,不针对实现编程。

/**
 * 这是上山路线的接口
 */
public interface IStrategyRoutes {

	// 上山路线信息
	void mcRoutesInfo();
}

这是为员工提供的路线A,路程最短。登山路线的不同,这也是这个需求(集合-登山-午餐)每个员工变化的部分,我们之所以把每种具体的上山路线都单独的封装起来,而不是将方法一个个的添加到各自员工类内部,是因为考虑到代码的复用,符合封装变化的OO原则

public class ShortestWalkRoutes implements IStrategyRoutes {
	
	@Override
	public void mcRoutesInfo() {
		System.out.println("上山路程最短");
	}

}

这是为员工提供的路线B,适合拍照,景色美:

public class CameraRoutes implements IStrategyRoutes {

	@Override
	public void mcRoutesInfo() {
		System.out.println("适合拍照,景色美");
	}

}

这是为员工提供的路线C,山路好走:

public class EasyRoadRoutes implements IStrategyRoutes {

	@Override
	public void mcRoutesInfo() {
		System.out.println("山路好走");
	}

}

同样我们可以将每个员工的共性抽离出来。在StaffBase类中加入接口类型变量(而不是具体的上山路线),每个员工都会动态的设置这个变量意在运行时引用正确的行为类型(例如:步行最少、适合拍照等),所以我们应该针对接口编程,而非针对实现编程。

/**
 * 这是一个员工类的基类
 */
public abstract class StaffBase {
	
	IStrategyRoutes routes;
	
	public void setRoutes(IStrategyRoutes routes){
		this.routes = routes;
	}
	
	// 针对接口编程,而不是具体实现,这样我们就不会把特定路线和特定员工死死的绑定在一起
	public void showStaffRoutes(){
		routes.trafficRoutesInfo();
	}
	
	// 将当前员工名字打印出来
	public abstract void showName();
	
}

登山时,员工可以选择适合自己的上山路线,如员工李四。这里采用静态工厂方法,让员工的代码与路线对象创建代码解耦。添加其他员工,我们只需要添加新类并继承StaffBase基类即可,不需要更改其他代码,符合对扩展开放,对修改关闭原则。

public class StaffOne extends StaffBase {
	
	public StaffOne(){
		// 员工李四默认选择了步行最少的路线
		// 此处之所以没有直接new主要是不想让员工和路线绑的死死的
		routes = RoutesFactory.getRoutes(1);
	}

	@Override
	public void showName() {
		System.out.print("本人李四");
	}

}

这是一个简单的静态工厂,目的是产生一些上山路线的对象。

public class RoutesFactory {
	
	public static IStrategyRoutes getRoutes(int type) {
		IStrategyRoutes routes;
		switch (type) {
		    case 1:
			    // 步行最少
			    routes = new ShortestWalkRoutes(); 
			    break;
		    case 2:
			    // 适合拍照,景色美
			    routes = new CameraRoutes(); 
			    break;
		    case 3:
			    // 容易好走
			    routes = new EasyRoadRoutes(); 
			    break;
		    default:
		        // 默认安全第一
			    routes = new EasyRoadRoutes(); 
			    break;
		}
		return routes;
	}
}

最后来个测试类吧,StaffOne 来采用距离最短方案上山。

public class StrategyPatternTest {

	public static void main(String[] args) {
		StaffBase staff1 = new StaffOne();
		staff1.showName();
		staff1.showStaffRoutes();
	}
}

再回头来看下策略模式的定义:我们定义了算法蔟,并分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。在本例中,上山具有不同的路线方案,都能达到到达山顶的目的,我们可称其为策略,而具体的路线策略变更对于员工无影响,员工只需知道选择方案1 可最短距离,具体的路线安排是A-B-C-D也好,A-C-B-D也罢,员工在登山之前并不关心。

栏目