JAVA设计模式之策略模式(strategy pattern)

编写鸭子项目,具体要求如下 :

1)有各种鸭子(比如 野鸭、北京鸭、水鸭等)鸭子有各种行为,比如叫、飞行等等。
2)显示鸭子的信息

项目进度1:

传统方案解决鸭子问题的分析和代码实现

1)传统的设计方案

public abstract class Duck {
	
	public Duck() {}
	
	// 显示鸭子信息
	public abstract void display();
	
	public void quack() {
		System.out.println("鸭子嘎嘎叫~~~");
	}
	
	public void swim() {
		System.out.println("鸭子会游泳~~~");
	}

}
public class ReadHeadDuck extends Duck {

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

}
public class MallardDuck extends Duck {

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

项目进度2:

现在,项目做到一半,领导要加需求,要让鸭子可以飞。

没办法,我们得老老实实干活,那么我们在Duck的超类里面加上fly()方法。

public abstract class Duck {
	
	public Duck() {}
	
	// 显示鸭子信息
	public abstract void display();
	
	public void quack() {
		System.out.println("鸭子嘎嘎叫~~~");
	}
	
	public void swim() {
		System.out.println("鸭子会游泳~~~");
	}
        public void fly() {
		System.out.println("鸭子会飞~~~");
	}

}

但是,刚这样更改完成之后,项目就出现了问题,原因是有一个橡皮鸭子,居然也可以飞了,这显然是不合道理的。出现这个问题的原因是在超类上面添加fly()方法,会导致所有的子类都具备fly(),连那些不应该具备的(例如橡皮鸭子)都可以飞了,我们想想有什么好的办法。

首先我们想到可以重载父类的fly()方法,让其实现为空就可以解决了。

可是,我们又加上了诱饵鸭子,它不会飞也不会叫,如果Duck里面的方法太多了,我们就得一个一个覆盖,太麻烦了。

到此为止,我们发现了继承来提供Duck的行为,会出现很多问题:1.代码在多个子类中重复2.运行时候的行为不容易改变3.很难知道所有鸭子的行为4。改变会牵一发而动全身,造成其它鸭子不想要的改变。

这个时候,我们又想到一个新的办法,将fly()方法抽取成一个接口,类图如下

但是这样以来,重复的代码会变得相当的多,对于相同的fly()行为,我们每一个新的会飞的鸭子都要自己实现,这将相当麻烦。

项目进度3:

设计原则:

  • 找出应用中可以需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。
  • 针对接口编程,而不是针对实现编程。

现在,我们的策略模式登场,我们将使用我们的设计模式来指导我们来改造我们的系统,来适应这些变化的需求。

策略模式(strategy pattern):

分开变化和不会变化的部分,Duck类的fly和quack()会随着鸭子的不同而改变,为了把这两个行为从鸭子类中分开,我们将其取出,建立一组新的类来代表每个行为。

这样设计的好处就是,可以让飞行和咕咕叫的动作被其它对象复用,因为这些动作已经与鸭子类无关了。而且我们也可以新增加一些行为类,也不会影响到使用飞行行为的鸭子类。,现在,我们可以按照策略模式来整合我们的代码了。

行为接口和部分实现类:

//咕咕叫行为接口
@FunctionalInterface
public interface QuackBehavior {
	public void quack();
}

public class FakeQuack implements QuackBehavior {
	public void quack() {
		System.out.println("Qwak");
	}
}

     
public class MuteQuack implements QuackBehavior {
	public void quack() {
		System.out.println("<< Silence >>");
	}
}      

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

//飞行类行为接口
@FunctionalInterface
public interface FlyBehavior {
	public void fly();
}

public class FlyNoWay implements FlyBehavior {
	public void fly() {
		System.out.println("I can't fly");
	}
}

public class FlyRocketPowered implements FlyBehavior {
	public void fly() {
		System.out.println("I'm flying with a rocket");
	}
}

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

鸭子超类:

public abstract class Duck {
	FlyBehavior flyBehavior;
	QuackBehavior quackBehavior;

	public Duck() {
	}

	public void setFlyBehavior(FlyBehavior fb) {
		flyBehavior = fb;
	}

	public void setQuackBehavior(QuackBehavior qb) {
		quackBehavior = qb;
	}

	abstract void display();

	public void performFly() {
		flyBehavior.fly();
	}

	public void performQuack() {
		quackBehavior.quack();
	}

	public void swim() {
		System.out.println("All ducks float, even decoys!");
	}
}

具体实现:

/**
 * 诱饵鸭,不能飞也不能叫
 */
public class DecoyDuck extends Duck {
	public DecoyDuck() {
		setFlyBehavior(new FlyNoWay());
		setQuackBehavior(new MuteQuack());
	}
	public void display() {
		System.out.println("I'm a duck Decoy");
	}
}
/**
 * 绿头鸭,可以叫也可以叫
 */
public class MallardDuck extends Duck {

	public MallardDuck() {

		quackBehavior = new Quack();
		flyBehavior = new FlyWithWings();

	}

	public void display() {
		System.out.println("I'm a real Mallard duck");
	}
}
/**
 * 模型鸭,不能飞但是可以叫
 */
public class ModelDuck extends Duck {
	public ModelDuck() {
		flyBehavior = new FlyNoWay();
		quackBehavior = new Quack();
	}

	public void display() {
		System.out.println("I'm a model duck");
	}
}
/**
 * 红头鸭,可以飞,也可以叫
 */
public class RedHeadDuck extends Duck {
 
	public RedHeadDuck() {
		flyBehavior = new FlyWithWings();
		quackBehavior = new Quack();
	}
 
	public void display() {
		System.out.println("I'm a real Red Headed duck");
	}
}
/**
 * 橡皮鸭,不能飞,吱吱叫
 */
public class RubberDuck extends Duck {
 
	public RubberDuck() {
		flyBehavior = new FlyNoWay();
		//quackBehavior = new Squeak();
		quackBehavior = () -> System.out.println("Squeak");
	}
	
	public RubberDuck(FlyBehavior flyBehavior, QuackBehavior quackBehavior) {
		this.flyBehavior = flyBehavior;
		this.quackBehavior = quackBehavior; 
	}
 
	public void display() {
		System.out.println("I'm a rubber duckie");
	}
}

下面给出测试类:

public class MiniDuckSimulator {
 
	public static void main(String[] args) {
 
		MallardDuck	mallard = new MallardDuck();
		FlyBehavior cantFly = () -> System.out.println("I can't fly");
		QuackBehavior squeak = () -> System.out.println("Squeak");
		RubberDuck	rubberDuckie = new RubberDuck(cantFly, squeak);
		DecoyDuck	decoy = new DecoyDuck();
 
		Duck model = new ModelDuck();

		mallard.performQuack();
		rubberDuckie.performQuack();
		decoy.performQuack();
   
		model.performFly();	
		model.setFlyBehavior(new FlyRocketPowered());
		model.performFly();
	}
}

注:@FunctionalInterface是函数式接口的注解,表明这个接口有且仅有一个抽象方法

在运行的时候想要改变鸭子的行为,只需要调用鸭子的setter方法即可。在整个新的设计中,我们已经可以动态的设定新的鸭子行为了,在鸭子的设计中,我们将两个行为类结合起来使用,这就是组合。这种做法和“继承”不同的地方在于,鸭子的行为不是继承来的,而是适当的和行为对象“组合”来的。

设计原则:

  • 多用组合,少用继承。

设计模式出炉:

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

在类结构设计中,我们可以换一个说法,我们将“一组行为”换成“一族算法”,算法代表鸭子可以做的事情,这样我们就可以理解策略模式的概念了,鸭子的行为的变化是可以独立于鸭子类的,完全可以动态设定。

下面是类图:

context:上下文对象,定义了各种算法策略

strategy:定义策略的接口

concreteStrategy:策略的具体实现

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值