码迷,mamicode.com
首页 > 其他好文 > 详细

策略模式(Strategy Pattern)

时间:2016-04-15 12:16:00      阅读:192      评论:0      收藏:0      [点我收藏+]

标签:

策略模式
策略模式:在我们的生活中其实就有很多这样的例子,比如我们我们要做一件事情,就说看书吧,A喜欢先看简介,然后看目录,然后在从第一章开始看,这就是看书的一种策略,B喜欢直接从第一章开始看,C喜欢直接看简介,然后看结尾。这是三种看书的方式,也就是所说的策略,对于策略,我的理解就是同一件事,对于不同的对象所匹配的一种执行事件的方式。策略模式是为了实现弱耦合的很好的方式。映射到程序员的世界里,策略就是算法了,策略模式就是处理同一件事,我可以有好几个不同的策略(算法)。

没事玩个鸡应用

污污公司开发了个应用叫没事玩个鸡,这是一款娱乐类应用,可以一键玩鸡,有不同品类的鸡给你玩,如三黄鸡、乌鸡、白鸡等。这个应用的内部设计是标准面向对象技术,设计了一个鸡超类(Superclass),让各种鸡继承此超类。我们来看一下代码:

</pre><pre name="code" class="java">	/** * 超类鸡 */
	abstract class Chicken {
		/** * 打招呼 */
		public void sayHi() {
			System.out.println("咯咯咯~");
		}

		/** * 鸡的样子,每种品类的鸡样子都不一样,所以该方法是抽象的 * 由具体的鸡来实现自己在屏幕上显示的样子 */
		public abstract void show();

	}

	/** * 白鸡,继承Chicken类 */
	class WhiteChicken extends Chicken {
		@Override
		public void show() {
			// 样子是白色的
		}
	}

	/** * 乌鸡,继承Chicken类 */
	class BlackChicken extends Chicken {
		@Override
		public void show() {
			// 样子是乌黑的
		}
	}

	/** * 尖叫鸡,继承Chicken类 */
	class ScreamChicken extends Chicken {
		/** * 尖叫鸡不会咯咯叫,所以重写sayHi()方法 */
		@Override
		public void sayHi() {
			System.out.println("惨叫声~");
		}

		@Override
		public void show() {
			// 样子是无毛的
		}
	}
代码很简单,具体品类的鸡继承超类(父类)鸡,所有的鸡都会叫,所以由父类处理。不同品类的鸡样子不同,所以由具体品类的鸡来实现。
没事玩个鸡应用很快火了,出现了很多竞争对手了,这时产品经理想要改变一些玩法来抛开竞争对手,想出了让鸡可以跑动,这样用户可就以玩跑动中的鸡了,程序员一想,这简单嘛,只需要在父类中加一个run()方法就可以了,这样所有品类的鸡都会跑了:
/** * 跑步 */ 
public void run() { 
	System.out.println("拼命跑"); 
}


改完后就交给测试人员去测


改完后就交给测试人员去测试去了。测试人员一测试,天了撸~出了个明显的bug啊,尖叫鸡也会跑!于是将bug提交到了系统中。

程序员一看,这确实不应该让尖叫鸡也能跑,先修复再说,于是他这样改了尖叫鸡类:

	/** * 尖叫鸡,继承Chicken类 */
	class ScreamChicken extends Chicken {
		/** * 尖叫鸡不会咯咯叫,所以重写sayHi()方法 */
		@Override
		public void sayHi() {
			System.out.println("惨叫声~");
		}

		@Override
		public void run() {
			// 覆盖,什么也不做
		}

		@Override
		public void show() {
			// 样子是无毛的 }
		}
	}



程序员重写了run()方法,然后什么也不实现,这样修复了bug。通过这个bug程序员也体会到了一件事:当涉及“维护”时,为了”复用(reuse)”目的而使用继承,并不太完美。

没事玩个鸡应用更新后更火了,于是产品经理决定每个月更新一次产品(至于更新的方法,他们还没有想到)。

程序员接到产品经理的更新计划就想,以后万一又要增加一些品类的鸡会怎样?万一有的功能部分品类的鸡是不具备的呢?那不是又得改父类又得改子类,牵一发而动全身,看来需要一个更好的方式才行。于是他开始翻看编程指南,终于找到一个设计原则。

设计原则

找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

换句话说,如果每次新的需求一来,都会使某方面的代码发生变化,那你就可以确定,这部分代码需要被抽出来,和其他稳定的代码有所区分,把变化的部分封装起来,以便以后可以轻易的改动或扩展此部分,而不影响不需要变化的部分。

分开变化和不会变化的部分

从哪里开始呢?我们知道Chicken类的sayHi()方法和run()方法会随着鸡的不同而改变,比如尖叫鸡sayHi()的方式就和别的鸡不一样,它也不会跑。根据上面说的设计原则,需要将它们独立出来,为了把这两个行为从Chicken类中分开,程序员将它们从Chicken类中取出来,建立一组新类来代表每个行为。示意图如下:

技术分享

现在已经把变化和不会变化的部分分开了,需要考虑如何设计鸡的行为类了。继续翻看编程指南,发现了另一个设计原则。

设计原则

针对接口编程,而不是针对实现编程。

现在程序员利用接口代表每个行为,比如,SayHiBehaviorRunBehavior,而行为的每个实现都将实现其中的一个接口。我们来看一下这两个接口的代码:

// SayHiBehavior接口:

	interface SayHiBehavior {
		void sayHi();
	}


	// RunBehavior接口:
	interface RunBehavior {
		void run();
	}


接口定义好了,我们就可以弄一些具体实现了。


普通的叫声:

public class NormalSayHi implements SayHiBehavior{

	@Override
	public void sayHi() {
		System.out.println("我是正常 的叫声");
	}

}

尖叫声:

public class ScreamSayHi implements SayHiBehavior{

	@Override
	public void sayHi() {
		System.out.println("我是尖叫哈哈哈");
	}

}

正常跑的行为:

public class NormalRun implements RunBehavior{

	@Override
	public void run() {
		System.out.println("我是正常的跑");
	}

}

快跑的行为:

public class FaseRun implements RunBehavior{

	@Override
	public void run() {
		System.out.println("我是飞快的跑");
	}

}

然后就重构下Chilcken这个父类:

public abstract class Chicken {

	private SayHiBehavior behavior;
	private RunBehavior behavior2;

	public abstract void show();//显示他的类别

	public void setSayHiBehavior(SayHiBehavior behavior) {
		this.behavior = behavior;
	}
	public void setRunBehavior(RunBehavior behavior) {
		this.behavior2 = behavior;
	}
	
	public void performSayHi(){//执行叫声
		behavior.sayHi();
	}
	
	public void performRun(){//执行跑
		behavior2.run();
	}
}
程序员将Chicken类的sayHi()方法和run()方法给注释掉了,增加了打招呼行为SayHiBehavior和跑步行为RunBehavior,通过setter来设置。然后用performSayHi()performRun()方法将具体的打招呼行为和跑步行为委托给SayHiBehaviorRunBehavior去做。


定义好实现的策略以后那么就看看使用吧。

public class Strategy {
	public static void main(String[] args){
		WhiteChicken chicken = new WhiteChicken();
		chicken.setRunBehavior(new NormalRun());//白鸡使用的跑的策略是正常跑
		chicken.setSayHiBehavior(new NormalSayHi());//叫声是使用的正常的叫声
		chicken.show();
		chicken.performRun();
		chicken.performSayHi();
		
		BlackChicken chicken2 = new BlackChicken();
		chicken2.show();
		chicken2.setRunBehavior(new FaseRun());
		chicken2.setSayHiBehavior(new ScreamSayHi());
		chicken2.performRun();
		chicken2.performSayHi();
	}
}

技术分享


这样就完美的实现了策略模式,可以根据你的需要,设置不同的策略,修改起来耦合性也比较低,不会对以前的代码有太大的影响。

总结

以上就是策略模式了,定义了算法族,分别封装起来,让他们之间可以互相替换。比如鸡的打招呼行为就有普通打招呼和惨叫打招呼,想用哪个就用哪个。在这里也使用了像多态组合来辅助实现策略模式。多用组合,少用继承也是一个设计原则。




策略模式(Strategy Pattern)

标签:

原文地址:http://blog.csdn.net/u012808234/article/details/51149796

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!