Java 策略模式

需求:游戏中有各种各样的鸭子,一边游泳戏水,一边呱呱叫。

解决方案:设计了一个鸭子超类,并让各个鸭子继承此类。

Duck.java
public abstract class Duck {
	public abstract void display();	
	public void quack(){
		System.out.println("呱呱叫!");
	}	
	public void swim(){		
		System.out.println("我会游泳");
	}
}
MallardDuck.java
public class MallardDuck extends Duck{
	@Override
	public void display() {
		System.out.println("我是绿头鸭!");
	}
}
ReadHeadDuck.java
public class ReadHeadDuck extends Duck{
	@Override
	public void display() {
		System.out.println("我是红头鸭!");
	}
}

需求变更:游戏需要有创新的地方,鸭子会飞。
解决方案:在Duck超类中加入fly()方法。
问题:因为所有的鸭子子类继承了Duck超类,橡皮鸭子竟然也会飞,不符合现实。

进一步的解决方案:在橡皮鸭子子类中覆盖父类的quack()方法和fly()方法。

Duck.java
public abstract class Duck {
	public abstract void display();	
	public void quack(){
		System.out.println("呱呱叫!");
	}	
	public void swim(){		
		System.out.println("我会游泳");
	}
	public void fly(){
		System.out.println("我会飞!");
	}
}

RubberDuck.java
public class RubberDuck extends Duck{
	@Override
	public void display() {
		System.out.println("我是橡皮鸭,我会吱吱叫,不会飞!");
	}	
	public void quack(){
		System.out.println("吱吱叫!");
	}	
	public void fly(){
		System.out.println();
	}
}


问题:现在又有一种鸭子为诱饵鸭,是木头假鸭,即不会叫也不会飞。
此时该如何解决了,如果再去覆盖父类中的方法,会发现这样会写很多无用的、重复的代码。

新的解决思路:使用接口,把fly()从超类中取出来,放进一个Flyable接口中,只有会飞的鸭子才实现此接口。
同样的方式,也可以设计一个Quackable接口,只有会叫的鸭子才实现此接口。

不过又有新的问题:使用接口,会造成代码不能复用,每个实现此接口的子类,都必须实现相应接口的方法。

再进一步思考:
    把问题归零,唯一不变得就是变化。
    
    把Duck类中的fly()和quack()方法取出来,建立一组新类代表每个行为。
    
    那么如何设计那组能实现飞行和呱呱叫的行为的类呢?
    
    我们希望一切都能有弹性,我们能够“指定”行为到鸭子的实例。
    
    例如:我们要产生一个新的绿头鸭实例,并产生特定“类型”的飞行行为给它。让鸭子的行为可以动态地改变。
    换句话说,我们应该在鸭子类中包含设定行为的方法,这样就可以在“运行时”动态地“改变”绿头鸭的飞行行为。

FlyBehavior.java
public interface FlyBehavior {
	public abstract void fly();
}

FlyNoWay.java
public class FlyNoWay implements FlyBehavior{
	@Override
	public void fly() {
		System.out.println("我不会飞!");
	}
}

FlyWithWings.java
public class FlyWithWings implements FlyBehavior{
	@Override
	public void fly() {
		System.out.println("我会飞!");
	}
}

QuackBehavior.java
public interface QuackBehavior {
	public abstract void quack();
}

Quack.java
public class Quack implements QuackBehavior{
	@Override
	public void quack() {
		System.out.println("呱呱叫");
	}
}

Squeak.java
public class Squeak implements QuackBehavior{
	@Override
	public void quack() {
		System.out.println("吱吱叫!");
	}
}

MuteQuack.java
public class MuteQuack implements QuackBehavior{
	@Override
	public void quack() {
	}
}

整合鸭子的行为:关键在于,鸭子现在会将飞行和呱呱叫的动作“委托”别人处理,而不是使用定义在
Duck类内的呱呱叫和飞行方法

Duck.java
public abstract class Duck {
	FlyBehavior flyBehavior;
	QuackBehavior quackBehavior; 	
	public abstract void display();		
	public void swim(){		
		System.out.println("我会游泳");
	}	
	public void performFly(){
		flyBehavior.fly();
	}	
	//鸭子对象不亲自处理呱呱叫行为,而是委托给quackBehavior引用的对象
	public void performQuack(){
		quackBehavior.quack();
	}
}
MallardDuck.java
public class MallardDuck extends Duck{	
	public MallardDuck() {
		//绿头鸭使用Quack类处理呱呱叫,所以当performQuack()被调用时,
		//叫的职责被委托给Quack对象,而我们得到了真正的呱呱叫。
		quackBehavior = new Quack();
		flyBehavior = new FlyWithWings();
	}	
	@Override
	public void display() {
		System.out.println("我是绿头鸭!");
	}
}

问题:我们的原则是不对具体实现编程,但是在构造器里仍然制造了一个具体的Quack实现类的实例!

思考:如何实现一个其行为可以在运行时改变的鸭子?

1.Duck超类添加set方法
Duck.java
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();
	}	
	//鸭子对象不亲自处理呱呱叫行为,而是委托给quackBehavior引用的对象
	public void performQuack(){
		quackBehavior.quack();
	}	
	//添加set方法,以后可以“随时”调用这两个方法改变鸭子的行为
	public void setFlyBehavior(FlyBehavior flyBehavior) {
		this.flyBehavior = flyBehavior;
	}	
	public void setQuackBehavior(QuackBehavior quackBehavior) {
		this.quackBehavior = quackBehavior;
	}		
}

2.添加一个火箭动力飞行的委托执行类
FlyRocketPowered.java
public class FlyRocketPowered implements FlyBehavior{
	@Override
	public void fly() {
		System.out.println("火箭动力飞行!");
	}
}

3.创建模型鸭
ModelDuck.java
public class ModelDuck extends Duck{
	public  ModelDuck() {
		flyBehavior = new FlyNoWay();//一开始,我们的模型鸭是不会飞的。
		quackBehavior = new Quack();
	}	
	@Override
	public void display() {
		System.out.println("我是模型鸭!");
	}
}

4.测试
Test.java
public class Test {	
	public static void main(String[] args) {
//		MallardDuck mduck = new MallardDuck();
//		mduck.display();
//		mduck.performFly();
//		mduck.performQuack();		
		
//		RubberDuck rd = new RubberDuck();
//		rd.display();
//		rd.quack();
//		rd.fly();
		
		//改变测试类,加上模型鸭,并使模型鸭具有火箭动力
		Duck model = new ModelDuck();
		model.performFly();
		model.setFlyBehavior(new FlyRocketPowered());
		model.performFly();
	}	
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值