设计模式之策略模式Strategy Pattern-Java版

一、策略模式定义

《Head First Design Patterns》:The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them
interchangeable. Strategy lets the algorithm vary independently from clients that use it.
即:策略模式定义了算法族,把算法族封装起来,使得它们之间可以切换。策略让算法独立于使用策略模式的客户端而变化。
简单说,就是可以来回切换算法。

 

 二、策略模式案例

案例:有父类鸭子,子类红头鸭、绿头鸭......实现鸭子的继承树,所有鸭子都会游泳,部分鸭子会飞,部分鸭子会叫。

版本一:单用继承

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

//绿头鸭
class MallardDuck extends Duck {

	@Override
	public void display() {
		System.out.println("绿头鸭");
	}
	
}
//红头鸭
class RedHeadDuck extends Duck {

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

分析:并不是所有鸭子都会飞,如家鸭,也并不是所有鸭子都会叫,如大黄鸭、小黄鸭。因此,单用继承不满足条件。


版本二:封装变化(面向对象设计原则一),将易变的部分从不变的地方分离出来,即将飞(Flyable)和叫(Quackable)作为接口从Duck类中分离出来,即面向接口编程(面向对象设计原则二),使得只有会飞的鸭子才实现Flyable接口,只有会叫的鸭子才实现Quackable接口。

public abstract class Duck {
	public void swim() {
		System.out.println("鸭子游泳!");
	}
	public abstract void display();
}

//飞的行为,接口
interface Flyable {
	void fly();
}

//叫的行为,接口
interface Quackable {
	void quack();
}

//水鸭子可以飞、游泳、叫
class WaterDuck extends Duck implements Flyable,Quackable {
	@Override
	public void quack() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void fly() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void display() {
		// TODO Auto-generated method stub
		
	}
	
}
//普通鸭子会游泳和叫
class NormalDuck extends Duck implements Quackable {

	@Override
	public void quack() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void display() {
		// TODO Auto-generated method stub
		
	}
	
}

分析:通过将飞的行为和叫的行为分离成接口,只有会飞的鸭子才实现飞的接口,只有会叫的鸭子才实现叫的接口,解决了“不是所有鸭子都会飞,不是所有鸭子都会叫”的问题。

然而,又遇到了新的问题,每只会飞的鸭子都要实现fly()方法,每只会叫的鸭子都要实现quack()方法,假设有两只鸭子都会飞,并且飞行方法都一样,但它们都要实现fly()方法,就出现代码的重复,也就是代码复用性不高,其次,若两只会飞的鸭子方法需要发生改变时,那么要修改多处,不能做到“一改全改”,改变时也容易引入新的bug。


版本三:创建Flyable模板(即实现该接口),创建Quackable模板,在Duck类中持有Flyable接口和Quackable接口的引用(面向对象原则三:组合优于继承),同时有set方法来更换飞行方式和叫的方式,set方法就是策略模式的核心,它可以实现飞行方式的切换、叫的方式切换。

public abstract class Duck {
	// 持有飞行行为的引用
	private Flyable fly = null;
	// 持有叫的行为的引用
	private Quackable quack = null;
	//构造方法,子类必须调用该方法
	public Duck(Flyable f, Quackable q){
		fly=f;
		quack=q;
	}
	// 改变飞行行为
	public void setFly(Flyable f) {
		fly = f;
	}

	// 改变叫的行为
	public void setQuack(Quackable q) {
		quack = q;
	}

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

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

	public void swim() {
		System.out.println("鸭子游泳!");
	}

	public abstract void display();

	public static void main(String[] args) {
		MallardDuck duck = new MallardDuck();
		duck.swim();
		duck.fly();
		duck.quack();
		duck.display();
		//set方法使得程序在运行期间,可以切换行为
		System.out.println("改变飞的行为、叫的行为后:");
		duck.setFly(new RocketPoweredFly());//改变飞的行为
		duck.setQuack(new LowVoiceQuack());//改变叫的行为
		duck.fly();
		duck.quack();
	}
}

//飞行接口
interface Flyable {
	void fly();
}

//不会飞
class FlyNoWay implements Flyable {
	@Override
	public void fly() {
		// do nothing
	}
}

//低空飞行
class LowHeightFly implements Flyable {
	@Override
	public void fly() {
		System.out.println("低空飞");
	}
}

//高空飞行
class HighHeightFly implements Flyable {
	@Override
	public void fly() {
		System.out.println("高空飞");
	}
}

//火箭式飞行
class RocketPoweredFly implements Flyable {
	@Override
	public void fly() {
		System.out.println("火箭升空");
	}
}

//叫的行为
interface Quackable {
	void quack();
}

//不会叫
class QuackNoWay implements Quackable {
	@Override
	public void quack() {
		// do nothing
	}

}

//尖叫
class ScreamQuack implements Quackable {
	@Override
	public void quack() {
		System.out.println("尖叫嘎嘎");
	}
}

//低声叫
class LowVoiceQuack implements Quackable {
	@Override
	public void quack() {
		System.out.println("低声嘎嘎");
	}
}

//绿头鸭
class MallardDuck extends Duck {

	public MallardDuck() {
		//高空飞,尖叫
		super(new HighHeightFly(),new ScreamQuack());
	}

	@Override
	public void display() {
		System.out.println("绿头鸭");
	}
}
//红头鸭
class RedHeadDuck extends Duck {
	
	public RedHeadDuck(){
		//不会飞,尖叫嘎嘎
		super(new FlyNoWay(), new ScreamQuack());
	}
	
	@Override
	public void display() {
		System.out.println("红头鸭");
	}
	
}

类图如下:

分析

  1. 将容易变化的部分即飞行和叫行为从不变Duck类中分离出来做成接口(封装变化);
  2. 飞行和叫有多个不同的实现,以增强代码的复用性(面向接口编程,提供模板以增加复用);
  3. Duck父类持有飞行和叫行为的引用,即使用组合(组合优于继承),同时提供setter方法,以实现不同行为的切换。

策略模式的应用场景

策略模式可以实现不同算法之间的来回切换,应用场景如,在游戏中,玩家可以任意切换武器或其他装备;在旅行过程中,可以中途换一种交通工具,公交-火车-飞机-taxi。总之,运行过程中,切换算法,就用策略模式,策略模式,用了的都说好(广告^v^)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学无止境jl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值