策略模式是什么?
策略模式定义了算法簇,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
策略模式解决什么问题?
如下继承结构中,父类Animal的两个通用方法会被子类(Dog、Duck)继承:
public class Animal{
public void quack(){
System.out.println("会叫");
}
public void run(){
System.out.println("会跑");
}
}
class Dog extends Animal{
}
class Duck extends Animal{
}
如果此时修改需求,需要让Animal会飞和会游泳
解决办法1
在Animal中添加fly()和swim()方法
public class Animal{
public void quack(){
System.out.println("会叫");
}
public void run(){
System.out.println("会跑");
}
public void fly(){
System.out.println("会飞");
}
public void swim(){
System.out.println("会游泳");
}
}
class Dog extends Animal{
@Override
public void fly() {
}
@Override
public void swim(){
}
}
class Duck extends Animal{
}
- Problem1:所有子类都会拥有这两个方法(包括不会飞和不会游泳的动物)
- Solution1:让不会飞的动物覆盖fly()方法并置空,不会游泳也同理
- Problem2:每当有新的动物(如Cat)继承Animal都要检查fly()和swim()方法
- Progrem3:哪天Dog学会游泳了,得重新修改Dog类源码中的swim()方法
解决办法2
新建flyable和swimable接口,让会飞和会游泳的动物去实现
public class Animal {
public void quack() {
System.out.println("会叫");
}
public void run() {
System.out.println("会跑");
}
}
interface flyable {
void fly();
}
interface swimmable {
void swim();
}
class Dog extends Animal {
}
class Duck extends Animal implements flyable, swimmable {
@Override
public void fly() {
System.out.println("会飞");
}
@Override
public void swim() {
System.out.println("会游泳");
}
}
- Progrem1:每当有新的动物(如Cat)都需要考虑实现flyable和swimmable
- Progrem2:代码变多且实现接口并没有代码复用
- Progrem3:哪天Dog学会游泳了,得修改Dog类源码实现swimmable并重写swim()方法
策略模式实现
定义算法簇
将不会变化的代码(quark、run)和会变化的代码(fly、swim)拆开,定义FlyBehavior和SwimBehavior接口,让其子类实现会飞/不会飞、会游泳/不会游泳:
interface FlyBehavior{
void fly();
}
class CanFly implements FlyBehavior{
@Override
public void fly() {
System.out.println("会飞");
}
}
class NoFly implements FlyBehavior{
@Override
public void fly() {
System.out.println("不会飞");
}
}
interface SwimBehavior{
void Swim();
}
class CanSwim implements SwimBehavior{
@Override
public void Swim() {
System.out.println("会游泳");
}
}
class NoSwim implements SwimBehavior{
@Override
public void Swim() {
System.out.println("不会游泳");
}
}
采用组合代替继承
Animal内部维护FlyBehavior和SwimBehavior父类实例,暴露公用set方法:
public class Animal {
private FlyBehavior flyBehavior;
private SwimBehavior swimBehavior;
public void quack() {
System.out.println("会叫");
}
public void run() {
System.out.println("会跑");
}
public void performFly(){
flyBehavior.fly();
}
public void performSwim(){
swimBehavior.Swim();
}
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public void setSwimBehavior(SwimBehavior swimBehavior) {
this.swimBehavior = swimBehavior;
}
}
针对多态编程
让Dog和Duck在初始化时,使用FlyBehavior和SwimBehavior的子类指定其行为:
class Dog extends Animal {
public Dog() {
setFlyBehavior(new NoFly());
setSwimBehavior(new NoSwim());
}
}
class Duck extends Animal {
public Duck() {
setFlyBehavior(new CanFly());
setSwimBehavior(new CanSwim());
}
}
运行时绑定
调用Dog的performSwim()方法时,因为构造函数内设置的是NoSwim()暂时还不会游泳:
Animal dog=new Dog();
dog.performSwim();
当Dog学会游泳时,可在不修改类源码的情况下重新指定其行为:
Animal dog=new Dog();
dog.setFlyBehavior(new CanSwim());
dog.performSwim();