策略模式:分别封装行为接口,实现算法组,超类里放行为接口对象,在子类里具体设定行为对象。原则就是:分离变化部分,封装接口,基于接口编程各种功能。此模式让行为算法的变化独立于算法的使用者。
策略模式注意点:1)分析项目中变化部分与不变部分;2)多用组合少用继承;用行为类组合,而不是行为的继承更有弹性。
鸭子游戏项目设计思路
一般设计是分析鸭子类别,把相同的放在抽象超类中实现,不同的在抽象超类中定义为抽象方法,然后不同的鸭子继承抽象超类,实现抽象方法
public abstract class Duck { public Duck() { } //鸭子都是一样的叫声 public void quack() { System.out.println("~~gaga~~"); } //鸭子都会游泳 public void swim() { System.out.println("~~im swim~~"); } //鸭子长相不一样 public abstract void display(); }
public class RedHeadDuck extends Duck { public void display() { System.out.println("**RedHead**"); } }
public class GreenHeadDuck extends Duck { public void display() { System.out.println("**GreenHead**"); } }
现在需求要改,鸭子会飞,那就给抽象超类添加一个fly方法,并实现会飞功能
public abstract class Duck { public Duck() { } //鸭子都是一样的叫声 public void quack() { System.out.println("~~gaga~~"); } //鸭子都会游泳 public void swim() { System.out.println("~~im swim~~"); } //鸭子长相不一样 public abstract void display(); //鸭子都会飞 public void fly() { System.out.println("~~fly~~"); } }
然后又改需求,说GreenHeadDuck不能飞了,那就要在GreenHeadDuck中覆盖父类fly方法
@Override public void fly() { System.out.println("**im cant fly**"); }
现在问题来了,就是在父类中实现了一个方法,如果有多个子类跟父类方法不一致,那就要每个不一致的子类都要重写父类方法;如果把超类中fly定义成抽象的,那么相同fly的代码不能重用了,使用和维护上麻烦了
又有个需求,stone duck既不会飞也不会叫,那么子类中要把fly和quack重写;所以父类挖坑要子类来填,这种设计并不是好的设计
项目设计方法:分析项目变化部分和不变部分,提取变化部分,抽象成接口+实现
以鸭子游戏项目为例,假如分析得出鸭子quack和fly是变化的
根据策略模式,把变化的行为抽象成接口,flybehavior和quackbehavior
超类中定义接口对象,接口对象调用相应方法,子类只对接口对象做对应的实例化即可
public interface FlyBehavior { void fly(); }
public interface QuackBehavior { void quack(); }
public class GoodFlyBehavior implements FlyBehavior { public void fly() { System.out.println("~~good fly~~"); } }
public class GaGaQuackBehavior implements QuackBehavior { public void quack() { System.out.println("~~ga ga ~~"); } }
public abstract class Duck { FlyBehavior flyBehavior; QuackBehavior quackBehavior; public Duck() { } public void fly() { flyBehavior.fly(); } public void quack() { quackBehavior.quack(); } public abstract void display(); public void swim() { System.out.println("~~swimming~~"); } }
public class GreenHeadDuck extends Duck { public GreenHeadDuck(){ this.flyBehavior=new GoodFlyBehavior(); this.quackBehavior=new GaGaQuackBehavior(); } public void display() { System.out.println("**GreenHead**"); } }
同样RedHeadDuck也可以像GreenHeadDuck一样,在自己的类中设定行为对象
这样有点问题就是一旦子类定义好,就不能动态改变行为了,那么就在超类中定义接口对象的set方法,可以使新实例化后的子类设定新的行为对象