策略模式

设计模式是人们在面对同类型软件工程设计问题所总结出的一些经验。模式不是代码,而是某类问题的通用解决方案。


思考引入:
设计一个鸭子类:鸭子有“”,“游泳”,“外形”各种行为。鸭子都可以叫,都会游泳,但是外形不一样。定义一个鸭子的超类,里面有“”,“游泳”这两个方法和一个“外形”的抽象方法留给子类实现,不同子类继承这个超类,定义出不同外形的鸭子类。

// 鸭子的超类
public abstract class Duck {
    public   void    quack(){
        System.out.print("gaga")
    }

    public   void    swim(){ 
       System.out.print("i  am swimming")  
    } 

    public   abstract    display(){   } 
}

现在有了新需求,给鸭子实现“”的功能,怎么办?
方式1:在超类里定义一个fly()方法,然后子类继承,就有了飞的功能。

// 鸭子的超类
public abstract class Duck {
    public   void    quack(){
        System.out.print("gaga")
    }

    public   void    swim(){ 
       System.out.print("i  am swimming")  
    } 

    public   abstract    display(){   } 

    public fly(){
        System.out.print("i can fly")
    }
}

这样行吗?好像是挺有道理的。那么问题来了,并不是所有鸭子都会飞,比如“玩具鸭”。这就需要“玩具鸭”这个子类自己去填坑修补这个“飞”的问题,一旦这样的子类很多,每个子类都要去填坑.
继承的问题:对类的局部改动,尤其是超类的改动,会影响其他部分。影响会有溢出效应。
方式2:在超类里定义一个fly()的抽象方法, 由子类自己去实现具体功能。或者直接定义一个fly的接口,子类实现该接口

// 鸭子的超类
public abstract class Duck {
    public   void    quack(){
        System.out.print("gaga")
    }

    public   void    swim(){ 
       System.out.print("i  am swimming")  
    } 

    public   abstract    display(){   } 

    public  abstra   fly(){ }
}

这样也可以实现该要求,但如果有很多子类都要实现fly功能,就需要分别实现该抽象放或者实现该接口。这种重复工作,代码的复用性很低。

这样,我们需要新的设计方式,对应项目的扩展性,降低复杂度。分析项目的变化与不变部分,提取变化部分,抽象成接口+实现。
1.定义行为接口

// 接口
public  interface  FlyBehavior{
  void fly();
}
public  interface  QuackBehavior{
  void quack();
}

2.定义出实现行为接口的行为(实现类),接口实现的各种行为类形成一个行为族。,如**“飞”,有的可以飞,有的不可以飞。有的鸭子“叫”**,有的叫声是“gaga”,有的叫声是“gege”.

// 叫声行为的行为族
// gaga叫的实现类
pubic  class  GagaQuack  implements  QuackBehavior{
    void quack(){
        System,out.print("gagaga...")  
    }
}
// gege叫的实现类
pubic  class  GegeQuack  implements  QuackBehavior{
    void quack(){
        System,out.print("gegege...")  
    }
}
// 飞行行为的行为族
// 可以飞行的实现类
pubic  class  CanFly  implements  FlyBehavior{
    void   fly (){
        System,out.print("i can fly ...")  
    }
}
// 不能飞行的实现类
pubic  class  CanNotFly  implements  FlyBehavior{
    void   fly (){
        System,out.print("i can't fly ...")  
    }
}

重新设计鸭子项目:

// 鸭子的超类
public abstract class Duck{
    QuackBehavior  quackBehavior;
    FlyBehavior  flyBehavior;

    Public  Duck(){}

    Pulic void quack(){
        quackBehavior.quack();
    }

    Pulic void fly(){
        flyBehavior.fly();
    }
    
    // 提供这个方法,可以动态改变他的行为
    public  void setQuackBehavior (QuackBehavior qBehavior){
        quackBehavior = qBehavior;
    }
    
  //swim方法和quack类似,此处就不重复写了。
}

定义一个可以飞,且gaga叫的绿头鸭子的“类”:

public  class GreenHeadDuck extends  Duck{
    public GreenHeadDuck (){
        QuackBehavior  qBehavior = new GagaQuackBehavior();
        FlyBehavior  fBehavior = new CanFly();
    }

    @Override
    public abstract display(){...}
}

定义一个gege叫,不会飞的玩具鸭的“类”:

public  class ToyDuck extends  Duck{
    public ToyDuck (){
        QuackBehavior  qBehavior = new GegeQuackBehavior();
        FlyBehavior  fBehavior = new CanNotFly();
    }

    @Override
    public abstract display(){...}
}

此时,通过new GreenHeadDuck()就可以创建一个可以飞,gaga叫绿头鸭的对象了。但是,我突然想让这个绿头鸭不gaga叫,而是gege叫,怎么办呢?再去重新定义一个类?这个时候就可以用鸭子超类里的setsetQuackBehavior方法了。通过

Duck gDuck = new GreenHeadDuck();
dDuck.quack();// 此时打印"gagaga..."
dDuck.setQuackBehavior(new GegeQuack());
gDuck.quack();//此时就打印"gegege..."

好处:这样,通过行为族的组合,用行为族里的对象来展现行为而不是把行为具体写在对象里。新增行为简单,行为类更好的复用,组合更方便。既有复用带来的复用的好处,没有挖坑。

这就是策略模式分别封装行为接口,实现算法族,超类里放行为接口对象,子类里具体设定行为对象。原则就是分离变化部分,封装接口,基于接口编程各种功能。此模式让行为算法的变化独立于算法的使用者。

策略模式注意点
1.分析项目中的变化与不变化部分。
2.多用组合少用继承;用行为类组合,而不是行为的继承,更有弹性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值