策略模式(Strategy Pattern)

在两个月前,我记得从网上别人的一篇总结设计模式的文章里看了十几个设计模式吧,除了自己做的时候经常使用到的封装好的模式以外的有点知道,基本都不记得怎么用了...
这本书我看了觉得真心不错所以推荐一下HeadFirst-DesignPattern

好了,来讲讲什么是策略模式吧,定义:定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

首先,来举个书上的例子吧,要做一个鸭子游戏,在游戏中有许多的鸭子种类和鸭子的行为。那该怎么把这些行为的种类和鸭子的种类联系起来呢,也许你会立马想到,利用OO嘛,面向对象就可以啦,那么假如有一千只鸭子每一只的行为都不同那么必须覆盖这个方法了,但是这些覆盖的方法都得要自己动手写那也是很麻烦的,还有一个问题就是,假如要为鸭子增加新的方法该怎么办呢?

我列出来几个点
1.相同的种类,相同的行为
2.相同的种类,不同的行为
3.不同的种类,相同的行为
4.不同的种类,不同的行为
5.新添加的种类,新添加的行为

那么该采用什么解决方法呢,其实应该用接口, 利用接口组合模式来替代继承模式,你可以调用多个接口但只能继承单一的类,多种属性不如用多个接口封装起来,然后为你需要调用的接口的添加的引用即可。这是书里着重强调的一点。

其次,要将不变的与可变的分开,对于不变的方法,鸭子游戏中无论是橡皮鸭子还是真的鸭子都是会游泳的,所以对于这个方法我们直接写在鸭子类中即可,而对于不同的行为,我们就必须要为这个行为定义不同的算法族封装成不同的接口了!
/*我们要实现的类从这个鸭子大类继承过去,各种类别的鸭子~*/
/*我们将固定的与可变的分开,固定的在这里完成,有各种具体形式的可变的从接口的引用实现*/
public abstract class Duck {
	FlyBehavior flybehavior;
	QuackBehavior quackbehavior;//叫
	
	public Duck(){}
	
	//鸭子的表现,这是必须要覆盖的方法
	public abstract void display();
	
	//这就是不变的方法直接在要继承的类中写明
	public void swim(){
		System.out.println("所有的鸭子都会游泳");
	}
	
	public void performFly(){
		flybehavior.fly();
	}
	
	public void performQuack(){
		quackbehavior.quack();
	}

	
	public void setFlyBehavior(FlyBehavior fb){
		flybehavior = fb;
	}
	
	public void setQuackBehavior(QuackBehavior qb){
		quackbehavior = qb;
	}
}

好啦,我们看看这个鸭子类吧,无论是什么种类的鸭子都是从这个鸭子类继承过去,所以它必须具有两个方面的东西:1.不可变方法;2.可变方法封装成接口的引用
这里面的FlyBehavior和QuackBehavior也就是我所说的接口的引用了,好,那么继续看看接口是怎么写的吧
/*飞这个行为的接口*/
public interface FlyBehavior {

	public void fly();

}
/*叫这个行为的接口*/
public interface QuackBehavior {
	
	public void quack();
	
}

这两个接口都非常的简单,他们里面只有两个方法是没有实现的,接口的方法是静态的,不能在接口中实现,这样子做其实好处多多啊,因为你每一个接口都有许多不同的行为,那么你可以分别取实现这些不同的行为了
/*飞的算法族*/
public class FlyWithWings implements FlyBehavior{

	public void fly() {
		// TODO Auto-generated method stub
		System.out.println("l'm flying!");
	}

}
/*飞的算法族*/
public class FlyNoWay implements FlyBehavior{

	public void fly() {
		// TODO Auto-generated method stub
		System.out.println("I can't fly");
	}

}
那现在你再好好想想如何利用这些算法吧~
是的没错,我们在类中定义了接口的引用,可以通过接口引用来实现。好了,想试试怎么使用接口的引用吗?在这之前我们还有个问题没有解决呢!
那就是我们需要不同的鸭子种类,首先我们来定义一个模型鸭子吧~
/*增加一个模型鸭类*/
public class modelDuck extends Duck{

	public modelDuck(){
		flybehavior = new FlyNoWay();
		quackbehavior = new MuteQuack();
	}
	
	public void display() {
		// TODO Auto-generated method stub
		System.out.println("a model duck");
	}
	
}
看到了吗,接口的引用我们是这么使用的呢~
  Duck modelduack = new modelDuck();
  modelduack.display();
  modelduack.performFly();
a model duck
I can't fly
这是打印出来的结果,我们要实现不同的鸭子的不同的行为就可以这么实现啦~想一想把所有鸭子的行为都定义在算法族里面的话是不是就不需要每次都覆盖了重新写了呢?

那么如果我们要修改算法族,新增加一个方法怎么办呢?那当然也是可以实现的哟~

首先我们往算法族里面添加这个算法
/*增加一个新的飞行算法*/
public class FlyRocketPowered implements FlyBehavior{
	
	public void fly() {
		// TODO Auto-generated method stub
		System.out.println("i'm flying with a rocket~");
	}

}
之前的Duck类中也看到了有一个setFlyBehavior()方法
public void setFlyBehavior(FlyBehavior fb){
		flybehavior = fb;
	}
那么我们来尝试着为我们的模型鸭设置这个新的飞行行为吧
Duck modelduack = new modelDuck();
		modelduack.display();
		modelduack.performFly();
		modelduack.setFlyBehavior(new FlyRocketPowered());
		modelduack.performFly();
a model duck
I can't fly
i'm flying with a rocket~
打印出来的结果还不错哟。

于是呢,我们现在无论想要在游戏中添加什么鸭子都可以直接new一个这个鸭子的对象,如果没有这类鸭子,也可以自己定义一个,它的方法呢,从算法族中可以轻易的实现了~
这就是第一个策略模式啦~










你可能感兴趣的:(策略模式(Strategy Pattern))