Strategy Pattern(策略模式)

(Strategy Pattern(策略模式)

引言

请不要染上“模式病”,……以后连写一个“Hello World” 都能够扯上模式,那就代表你已经病了… …
谨做记录,以便以后浏览

需求

本文从鸭子这种可爱又好吃的小动物来展开,但是我们今天不说如何吃它,而且讨论如果优雅的实现鸭子的一些特定行为。

  1. 每只鸭子都会游泳、叫。
  2. 事实上有些鸭子会飞、有些鸭子并不会。
  3. 给鸭子加持火箭动力,使其成为火箭动力鸭。
  4. 针对接口编程,而不是针对实现编程

一、实现鸭子超类

public abstract class Duck {
	//叫
	public void quack(){}
	//游泳
	public void swim(){}
	//特征方法
	public abstract void display();
}

鸭子的超类决定了鸭子具有游泳display三个特性。

二、改变某些鸭子的行为
到这里可能大家会说,这不就写个父类继承吗?
对,你说的没错。这时我们的第一个问题来了:
假设现在已经诞生了很多只鸭子,而需要有些鸭子可以飞行,怎样实现会好一点?

给鸭子超类编写一个飞行方法?

// 飞行
public void fly() {
	System.out.print("我是会飞的鸭子");
}

这样会造成所有的鸭子子类都具有了飞行的特性,而不是部分。

三、放弃继承,使用接口
既然继承无法完美的实现功能,那么得另辟蹊径,去寻找新的方法来解决问题,首先,想到了接口。
可以将 quack()fly()Duck中分离出来。
创建 Iquack 接口和 Ifly 接口,然后让需要实现 quackfly 的鸭子去实现对应的接口。
这样比继承棒多了,再也不会看到橡皮鸭子叫着在天上飞了。

但是这样重复的代码会变多,在需要修改的子类个数较少时还能应付。
那么对成百上千个鸭子修改一下飞行的行为就会变得繁杂。
虽然使用接口解决了一部分问题,但是却造成代码无法复用。
这只能算是从一个噩梦跳进了另外一个噩梦
甚至,在会飞的鸭子中,飞行的行为也是多变的
或许就有一只鸭子是使用火箭动力系统来飞行

四、再次明确问题
至此还是没有找到解决问题的好方法,把问题归零梳理:

  1. 继承并不能很好的解决问题,因为鸭子的行为在子类不停的改变。
  2. 接口解决了问题,但是java接口不具有实现代码,所以继承接口无法达到代码的复用

五、策略模式
使用策略模式可以应对这种问题,策略模式的思路是:
找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
按照这个思路,要分离出来的变化之处就是 quack()fly()
并且我们要按照针对接口编程,而不是针对实现编程原则
首先定义两个接口 QuackBehaviorFlyBehavior

六、新的实现
创建 FlyWithWings 类实现 IFlyBehavior //会飞
创建 FlyNoWay 类实现 IFlyBehavior //不会飞
创建 Quack类实现 IQuackBehavior //会叫
创建 Squeak类实现 IQuackBehavior //会说话

这样的设计,可以让的动作被其他对象复用,因为这些行为已经与Duck无关了,而我们新增的一些行为,不会影响到既有的行为类。

public interface IFlyBehavior {
	void fly();
}
public interface IQuackBehavior {
	void quack();
}

然后将这两个接口整个到鸭子的超类。

public abstract class Duck {
	public IFlyBehavior iFlyBehavior;
	public IQuackBehavior iQuackBehavior;
	// 游泳
	public void swim() {}
	// 特征方法
	public abstract void display();
	// 执行 飞
	public void performFly() {
		iFlyBehavior.fly();
	}
	// 执行 叫
	public void performQuack() {
		iQuackBehavior.quack();
	}
}

使用接口实例,将fly和quack委托给行为类
这样就可以在实例化鸭子对象的时候,通过行为的不同来让鸭子实现特定的行为。
在实例化行为的时候,使用特定的行为类。

public class RedDuck extends Duck {
	public RedDuck() {
		iFlyBehavior = new FlyWithWings();
		iQuackBehavior = new Quack();
	}
	@Override
	public void display() {
		System.out.println("红色鸭子");
	}
}

到此,我们的设计总算成功了。
七、测试
更加深入一步,通过这样的设计,可以在运行时去动态的改变鸭子的行为。
上面的实现是需要在构造器去定制鸭子的行为。
现在鸭子不在是一只只会嘎嘎叫的鸭子了,它可以一飞冲天
将Duck和行为分开后,降低了耦合,提升了复用,最重要的是让代码的可扩展性得到了质的提升
如何在运行时去改变鸭子的行为。
首先我们想到Duck里面的行为接口实例。
通过改变接口的实现,来在运行时改变鸭子的行为。
添加setter方法,这样就可以动态的设置鸭子子类行为接口的实现

public static void main(String[] args) {
   	RedDuck redDuck = new RedDuck();
   	redDuck.setiFlyBehavior(new Rocket());
   	redDuck.performFly();
   }

运行结果:
火箭动力飞行

不知不觉,程序已经完善了,很神奇,这就是Strategy Pattern策略模式。

参考:《Head First Java》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值