设计模式之策略模式

Head First 设计模式学习,约定以代码开始,结束时附上定义。

Duck鸭子游戏,要设计一款游戏,初始要求游戏中有各种鸭子,一边叫一边游泳,每种鸭子外观不同。

这很容易实现,一个父类有一个会呱呱叫的方法quack(),和一个会游泳的方法swim(),还有一个抽象方法display()表示外观,不同的子类继承它,实现自己的外观就行。


//鸭子父类
public abstract class Duck {

	public void quack(){
		System.out.println("呱呱叫");
	}
	public void swim(){
		System.out.println("游泳");
	}
	
	public abstract void display();
}
//红头鸭实现
public class RedHeadDuck extends Duck{

	@Override
	public void display() {
		System.out.println("红头鸭 鸭头是红色");
	}

}
红头鸭继承父类,那么他就会叫和会游泳,自己实现了自己的外观。貌似这样不错。

接下来游戏要改,要求加入会飞的鸭子,我们能在父类中直接写么?我们应该知道不是所有的鸭子都会飞的。但貌似也可以在父类中去写,因为我们可以用子类去覆盖父类的方法。但是要考虑到如果以后有多个不会飞的鸭子加进来,那每个不会飞的鸭子都要复写父类方法,这可不是个好的现象。甚至如果有些鸭子不会叫,或者不会呱呱叫只会吱吱叫怎么办?子类都要覆盖?看来我们得想其他的方法去做这个游戏。


那么我们把会飞的方法fly(),和叫声的方法quack(),提取出来怎么样,提取两个接口Flyable和Quackable.父类Duck只有会游泳swim()方法和一个抽象的display()方法,毕竟每个鸭子都会游泳。只要是子类就继承父类,会飞的就实现Flyable接口实现fly方法,会叫怎么叫都实现Quackable接口实现quack()方法。但是要想到大部分鸭子都会叫并且都是呱呱叫,那么我们都要实现Flyable并且每个类中的方法都是一样的,重复代码变多,并且如果要改一下叫的行为,就要大量修改代码。简直是噩梦,不能复用,大量重复的代码。看来这种方法也不好。RubberDuck橡皮鸭,不会飞


是什么原因造成上面的问题呢?主要是fly与quack对于子类来说是可变的,我们无法预测每只鸭子的具体的行为是怎么样的。那怎么解决,我是不是能把fly与quack的具体的行为抽离出来分别做成一组,那么Duck,子类Duck,和具体的行为就分开了。这样之后具体行为是怎么用的呢?子类直接继承?明显不行子类还要继承父类Duck呢;父类继承?那和开始做的第一个版本有什么区别;子类持有引用?代码大量重复,每个子类都要有这两个引用;那么只能父类持有两个引用了,这也是唯一好的解决办法,但是我们又想要子类可以指定自己的行为,父类的引用肯定不能是具体类,应该是个接口,所有具体行为应该实现统一接口。

FlyBehavior和QuackBehavior为两个接口,FlyWithWings为FlyBehavior实现类,可以飞。FlyNoWay为FlyBehavior实现类。不可以飞。Quack,Squeck,NoQuack为QuackBehavior的实现类,分别表示呱呱叫,吱吱叫,什么也不做不能叫。

Duck持有两个接口的引用,并且有两个方法去调用接口的方法。当然可以动态设置,两个接口都有set方法。我们去代码实现

扫描二维码关注公众号,回复: 63353 查看本文章
public interface QuackBehavior {

	public void quack();
}
public interface FlyBehavior {

	public void fly();
}
public class FlyWithWings implements FlyBehavior{

	@Override
	public void fly() {
		System.out.println("fly");
	}

}
public class Squack implements QuackBehavior {

	@Override
	public void quack() {
		System.out.println("吱吱叫");
	}

}
public abstract class Duck {

	protected FlyBehavior flyBehavior;
	protected QuackBehavior quackBehavior;
	
	public void quack(){
		quackBehavior.quack();
	}
	
	public void fly(){
		flyBehavior.fly();
	}
	public void setFlyBehavior(FlyBehavior flyBehavior) {
		this.flyBehavior = flyBehavior;
	}
	public void setQuackBehavior(QuackBehavior quackBehavior) {
		this.quackBehavior = quackBehavior;
	}
	
	public abstract void display();
	
}
public class RedHeadDuck extends Duck{
	public RedHeadDuck(){
		flyBehavior=new FlyNoWay();
		quackBehavior=new Quack();
	}
	@Override
	public void display() {
		System.out.println("红头鸭");
	}
}
public class Test {

	public static void main(String[] args) {
		Duck duck=new RedHeadDuck();
		duck.quack();
		duck.fly();
		duck.setFlyBehavior(new FlyWithWings());
		duck.setQuackBehavior(new Squack());
		duck.quack();
		duck.fly();
	}
}

测试的结果是

呱呱叫
can not fly
吱吱叫
fly

可以看出中间可以动态改变鸭子的行为。这时如果再有新的鸭子加入,有不同的行为直接再创建行为类即可。甚至改变原有的行为,只要改变行为类,Duck与应用类都不需要改变。

策咯模式定义:策咯模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

对照讲解解释下,算法族这里指的是行为类即fly与quack,我们针对接口分别封装起来,每个行为封装为一个类。可以互相替换即面向接口变成,具有set方法,可以动态变化行为。最后真的客户完全不关心你算法的实现,和自己一点关系没有。





猜你喜欢

转载自blog.csdn.net/cgj296645438/article/details/80074319