策略模式

最近在看《Head First设计模式》,老外写的书真心是幽默风趣,通俗易懂,这个系列应该有至少13篇,权当读书笔记了。
学习之前我们需要了解以下基本前提:
学习设计模式不是为了设计模式本身,而是要明白这种设计为什么好,跟我们自己的实现有什么区别,我们自己最初的想法为什么就渣,明白这种对比的优缺点,

策略模式(Strategy Pattern)
需求:一个模拟鸭子的游戏,需要设计一个鸭子的超类,需要有:瓜瓜叫(quack)、飞(fly)、展示(display) 的行为方法。


普通的方法一:设计鸭子的超类Duck,然后其它所有的的鸭子继承自这个超类,如下图:


游戏中出现了问题,现在有一只橡皮鸭,继承了Duck,它也飞起来了,显然这是不合适的行为,而且橡皮鸭是吱吱叫(squeak),不是呱呱叫。
针对上面的问题我们都知道一般的方法就是覆盖掉fly()和quack(),前者方法体什么都不做,后者重写为吱吱叫。
以上设计的缺点:
1.代码在多个子类中重复了
2.很难知道鸭子的全部行为,要在一个Duck中将鸭子所有的行为都体现出来,很难穷尽
3.运行时行为不容易改变,就是无法动态set一些行为
4.改变会导致牵一发动全身,造成其它鸭子不想要的改变,例如木头鸭子不会飞不会叫
5.每次新增一个鸭子类,需要检查里面所有的方法,调处需要覆盖的覆盖掉,这显然是太恐怖了



普通的设计二:
将fly、quack设计成接口,如下图


这种设计会出现很多重复的代码,所有的鸭子都需要将fly、quack实现一遍,特别是游戏,一群鸭子的时候,要实现一群fly,疯掉了,怎么办?

设计原则1:
找出应用中可能需要变化之处,把它独立出来,不要和那些不需要变化的代码混在一起。就是说把变化的部分提取出来并封装,以后可以轻易的改动或者扩展此部分,
而不影响其它不需要改动的部分。就是说我们需要把鸭子的行为从Duck中分离出来。刚才的普通设计二也是一种分离,但显然是不可行的,怎么办呢?
设计原则2:针对接口编程,而不是针对实现编程,设计二显然针对实现在编程。鸭子的行为应该被放在分开的类中,此类已经专门实现了行为接口,这样鸭子本身是不要知道
行为的具体细节(就是自己不用再去实现了,我管毛啊,已经有别的行为类在管
了),像下面这样:


还要说一点,针对上面,有人会问,为毛还在用接口,直接用抽象超类啊,其实也是可以的。我们理解一下上面的设计的思路,针对接口编程的真正用意就是针对超类编程,
通常是一个抽象超类或者接口,我们在申明类的时候,不用管以后执行类的真正类型,例如上面,我只有申明FlyBehavior类型的变量就可以,我管你具体的执行类是
能飞不能飞怎么飞呢,who cares?


上面说了那么多,不废话了,直接拿出最终方案了,先上图:


在超类Duck,加入了flyBehavior、quackBehavior两个变量,perforQuack、performFly方法,以及set方法

<span style="font-size:18px;">public clas Duck{

	QuackBehavior quackBehavior;
	FlyBehavoir flyBehavoir;
	
	public void setFlyBehavior(FlyBehavoir fb){
		flyBehavoir = fb;
	}
	
	public void setQuackBehavior(QuackBehavior qb){
		quackBehavior = qb;
	}
	
	public void perforQuack(){
		quackBehavior.quack();
	}
	
	public void perforFly(){
		flyBehavoir.fly();
	}
}</span>

子类,以MallardDuck为例

<span style="font-size:18px;">public class MallardDuck ectends Duck{
	public MallardDuck(){
		quackBehavior = new Quack();
		flyBehavoir = new FlyWithWings();
	}
	
	public void display(){
		System.out.println("I'm a real Mallard duck");
	}
}</span>

FlyBehavoir接口以及具体实现类

<span style="font-size:18px;">public interface FlyBehavoir{
	public void fly();
}

public class FlyWithWings implements FlyBehavoir{
	public void fly(){
		System.out.println("I'm flying!");
	}
}

public class FlyNoWay implements FlyBehavoir{
	public void fly(){
		System.out.println("I can't fly");
	}
}</span>

QuackBehavior接口以及具体实现类

<span style="font-size:18px;">public interface QuackBehavior{
	public void quack();
}

public class Quack implements quackBehavior{
	public void quack(){
		System.out.println("Quack");
	}
}

public class Squeak implements quackBehavior{
	public void quack(){
		System.out.println("Squeak");
	}
}

public class MuteQuack implements quackBehavior{
	public void quack(){
		System.out.println("Slience");
	}
}</span>

针对以上的策略设计模式,有以下总结:
1.“有一个”可能比“是一个”更好
2.多用组合,少用继承



最后,策略模式的定义:
定义算法族,分别封装起来,让他们之间彼此可以替换,此模式让算法的变化独立于使用算法的客户。
这里的算法就是鸭子的fly和quack,使用这些算法就是鸭子类,这样理解起来是不是清晰很多。


------------------------------------------------over-------------------------------------------------


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值