策略模式

策略模式

策略模式也是23种设计模式之一。

策略模式是指将程序中可变部分抽象分离成一系列的算法,并将每一个算法封装起来,而且使他们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

策略模式一般由下面三部分组成:

1. 抽象策略角色: 策略类,通常由一个接口或者抽象类实现。 

2. 具体策略角色:包装了相关的算法和行为。 
3. 环境角色:持有某一个策略类的引用,客户端调用。 

策略模式设计原则: 
1. 把程序中需要变化的部分抽离出来,独立于不变的部分。 
2. 面向接口编程,而不是面向实现编程,多用组合,少用继承。

(组合 :在类中增加一个私有域,引用另外一个已经有的类的实例,通过调用实例的方法从而获得新的功能)


我们以鸭子(Duck)做一个例子。

鸭子有哪些行为呢?

行为:游泳,飞。

所有的鸭子都会游泳我们是知道的,但是所有的鸭子都会飞嘛?

真鸭子会飞,那假鸭子呢?

答案是否定的,依照我们策略设计模式的原则,我们需要把程序中需要变化的部分抽离出来,也就是要把鸭子会飞的行为抽离出来。

在抽离之前,我们先来把不需要分离的部分写出来。

鸭子都会游泳,是一个共有的行为,那么我们把游泳的行为写进抽象鸭子类(Duck)中。

Duck.java代码:

public abstract class Duck {
	public void swing(){
		System.out.println("我会游泳!!!");
	}
	public void play(){
		swing();
	}
}
共有的行为写完了,那么我们就来写飞的行为,因为有些鸭子会飞,有些鸭子不会飞,所以飞行行为的实现是不同的。

我们创建一个FlyBehavior的接口,让子类去实现不同的行为。

FlyBehavior.java代码:

public interface FlyBehavior {
	public void fly();
}
然后我们再创建两个类来继承这个接口,实现不同的飞行行为。

FlyWithWing.java代码:

public class FlyWithWing implements FlyBehavior{
	@Override
	public void fly() {
		System.out.println("我会飞!!!");
	}	
}
FlyNoWay.java代码:
public class FlyNoWay implements FlyBehavior{
	@Override
	public void fly() {
		System.out.println("很遗憾,我飞不起来。。。");
	}
}

这下子,我们把鸭子飞的行为也写完了,那么我们是不是需要把它们组合起来呢。

再次申明下组合的概念:

组合 :在类中增加一个私有域,引用另外一个已经有的类的实例,通过调用实例的方法从而获得新的功能。

我们需要在Duck类中增加一个私有域,引用FlyBehavior的实例,通过调用它的fly();方法来获得相应的飞行能力。

我们重新修改下Duck类。

修改后的Duck.java代码:

public abstract class Duck {
	private FlyBehavior flyBehavior;
	public void setFlyBehavior(FlyBehavior flyBehavior) {
		this.flyBehavior = flyBehavior;
	}
	public void fly(){
		flyBehavior.fly();
	}
	public void swing(){
		System.out.println("我会游泳!!!");
	}
	public void play(){
		swing();
		fly();
	}
}
flyBehavior属性就是引用的那个私有域,我们为这个属性写上set方法的原因是为了之后能够更好的根据我们的需求而变化。

在fly();方法里面我们调用了flyBehavior的fly();方法,这样我们通过实例化FlyBehavior接口的不同子类来实现flyBehavior.fly()的动态改变。

接下来我们写一个真鸭子的子类来继承抽象Duck类。

RealDuck.java代码:

public class RealDuck extends Duck{
	public RealDuck(){
		super.setFlyBehavior(new FlyWithWing());
	}
}
我们把假鸭子的代码也写出来。

RubberDuck.java代码:

public class RubberDuck extends Duck{
	public RubberDuck(){
		super.setFlyBehavior(new FlyNoWay());
	}
}
这样下来,我们的真鸭子和假鸭子都通过自己的构造方法为flyBehavior属性实例化了不同的飞行行为。

我们用真鸭子为例,来测试下,新建一个DuckTest类。

DuckTest.java代码:

public class DuckTest {
	public static void main(String[] args){
		RealDuck realDuck=new RealDuck();
		realDuck.play();
	}
}
控制台输出结果:

我会游泳!!!
我会飞!!!

我们不需要知道飞行行为的具体实现,我们只需要根据自己的需求实例化不同的FlyBehavior接口子类就OK了。

通过这个实现,我们让可变的飞行行为独立于鸭子类本身,这样可便于后期的维护和拓展。


比如我们现在想写一只超级鸭子,它具有火箭推动的飞行能力,在我们之前的FlyBehavior接口子类中并没有这个飞行行为。

那么我们只需要重新写一个火箭推动的飞行类即可。继承FlyBehavior接口。

FlyWithRocketPower.java代码:

public class FlyWithRocketPower implements FlyBehavior{
	@Override
	public void fly() {
		System.out.println("我用火箭来推动我飞行!!!");
	}
}
火箭推动的飞行行为我们写好了,然后再写一只超级鸭子即可。

SuperDuck.java代码:

public class SuperDuck extends Duck{
	public SuperDuck() {
		super.setFlyBehavior(new FlyWithRocketPower());
	}
}
我们再来测试一下超级鸭子,修改下测试类就好了。

修改后的DuckTest.java代码:

public class DuckTest {
	public static void main(String[] args){
		SuperDuck superDuck=new SuperDuck();
		superDuck.play();
	}
}
控制台输出结果:

我会游泳!!!
我用火箭来推动我飞行!!!


通过以上实例,我们将具有不同行为实现的飞行行为与鸭子基类分离,让它独立于鸭子类而变化。

这让我们在后期需求发生变化或者要求新的功能时,大大减少我们的代码量,我们只需要实现相应的接口即可。

让我们面向接口编程。
这就是策略模式!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值