您现在的位置是:首页 >技术杂谈 >设计模式-策略模式网站首页技术杂谈
设计模式-策略模式
问题背景
编写一个鸭子项目
1、有各种各种的鸭子,他们有各种行为,例如游泳,飞行,叫等
2、野鸭会飞,会游泳,会叫
3、水鸭不会飞,会游泳,会叫
4、玩具鸭不会飞,不会游泳,会叫
展示这些鸭子的行为
解决方案:传统方式
我们来想想传统的解决方式
1、每一个鸭子都写一个类,这样确实没有什么问题。但是它的缺点就是方法不能复用,重复的方法要写好多。
2、我们比较一看上面的信息,我们发现,其实他们就是三种行为,只不过对这三种行为有不同的表现,例如,飞行,野鸭会飞,水鸭和玩具鸭不会。
3、所以我们就就来向上抽象,抽象类中实现所有的方法, 不同的鸭子如果和抽象类不同,那就在子类中重写方法。
4、但是这样也不对,其实对于水鸭和玩具鸭本质就是不会飞的。
4、这就是继承带来的问题,对类的局部改动,尤其是超类的局部改动,会影响其他部分,会有溢出效应
策略模式
基本介绍
1)策略模式(Strategy Pattern)中,定义算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户
(就是对我们的鸭子的行为单独拿出来做一个接口,然后实现不同的行为,例如将飞行这种行为拿出来作为接口,然后再继承这个接口实现会飞,飞的不好,不会飞这三种形式,不同的鸭子传入不同的形式就可以了)
2)这算法体现了几个设计原则,第一、把变化的代码从不变的代码中分离出来;第二、针对接口编程而不是具体类(定义了策略接口);第三、多用组合/聚合,少用继承(客户通过组合方式使用策略)
UML类图
从上面的类图我们可以看到,Context类有成员变量StrategyA和StrategyB接口,需要那个接口我们就在构造器中执行。
使用策略模式解决问题
UML类图
代码示例
/**
* 鸭子抽象类
*/
public abstract class Duck {
public void quack() {
System.out.println("会叫");
}
}
/**
* 飞行行为
*/
public interface FlyBehavior {
void fly();
}
/**
* 游泳行为
*/
public interface SwimBehavior {
void swim();
}
/**
* 水鸭
*/
public class TealDuck extends Duck{
private SwimBehavior swimBehavior;
private FlyBehavior flyBehavior;
private String name = "水鸭";
public String getName() {
return name;
}
public TealDuck(SwimBehavior swimBehavior, FlyBehavior flyBehavior) {
this.swimBehavior = swimBehavior;
this.flyBehavior = flyBehavior;
}
public void swim() {
if (swimBehavior != null) {
swimBehavior.swim();
}
}
public void fly() {
if (flyBehavior != null) {
flyBehavior.fly();
}
}
}
/**
* 野鸭
*/
public class WildDuck extends Duck{
private SwimBehavior swimBehavior;
private FlyBehavior flyBehavior;
private String name = "野鸭";
public String getName() {
return name;
}
public WildDuck(SwimBehavior swimBehavior, FlyBehavior flyBehavior) {
this.swimBehavior = swimBehavior;
this.flyBehavior = flyBehavior;
}
public void swim() {
if (swimBehavior != null) {
swimBehavior.swim();
}
}
public void fly() {
if (flyBehavior != null) {
flyBehavior.fly();
}
}
}
/**
* 玩具鸭
*/
public class ToyDuck extends Duck{
private SwimBehavior swimBehavior;
private FlyBehavior flyBehavior;
private String name = "玩具鸭";
public String getName() {
return name;
}
public ToyDuck(SwimBehavior swimBehavior, FlyBehavior flyBehavior) {
this.swimBehavior = swimBehavior;
this.flyBehavior = flyBehavior;
}
public void swim() {
if (swimBehavior != null) {
swimBehavior.swim();
}
}
public void fly() {
if (flyBehavior != null) {
flyBehavior.fly();
}
}
}
飞行行为
public class BadFlyBehavior implements FlyBehavior{
@Override
public void fly() {
System.out.println("飞的不好");
}
}
public class GoodFlyBehavior implements FlyBehavior{
@Override
public void fly() {
System.out.println("飞的很好");
}
}
public class NotFlyBehavior implements FlyBehavior{
@Override
public void fly() {
System.out.println("不会飞");
}
}
游泳行为
public class BadSwimBehavior implements SwimBehavior{
@Override
public void swim() {
System.out.println("游的不好");
}
}
public class GoodSwimBehavior implements SwimBehavior{
@Override
public void swim() {
System.out.println("游的很好");
}
}
public class NoSwimBehavior implements SwimBehavior{
@Override
public void swim() {
System.out.println("不会游泳");
}
}
测试类
public class Client {
public static void main(String[] args) {
ToyDuck toyDuck = new ToyDuck(new NoSwimBehavior(), new NotFlyBehavior());
System.out.println(toyDuck.getName());
toyDuck.quack();
toyDuck.fly();
toyDuck.swim();
System.out.println("========================================================");
WildDuck wildDuck = new WildDuck(new GoodSwimBehavior(), new GoodFlyBehavior());
System.out.println(wildDuck.getName());
wildDuck.quack();
wildDuck.fly();
wildDuck.swim();
System.out.println("========================================================");
TealDuck tealDuck = new TealDuck(new BadSwimBehavior(), new BadFlyBehavior());
System.out.println(wildDuck.getName());
wildDuck.quack();
wildDuck.fly();
wildDuck.swim();
System.out.println("========================================================");
}
}
测试结果
注意事项和细节
1)策略模式的关键是:分析项目中变化部分与不变部分
2)策略模式的核心思想是:多用组合/聚合,少用继承;用行为类组合,而不是行为的2继承。更有弹性
3)体现了“对修改关闭,对扩展开放”原则,客户端增加行为不用修改原有代码,只要添加一种策略 (或者行为) 即可,避免了使用多重转移语句 (if…else if…else)
4)提供了可以替换继承关系的办法:策略模式将算法封装在独立的Strategy类中使得你可以独立于其Context改变它,使它易于切换、易于理解、易于扩展
5)需要注意的是:每添加一个策略就要增加一个类,当策略过多是会导致类数目庞大