策略模式
策略模式属于行为模式中的一种。当不同对象执行同一动作时,表现出不同的形式。如有很多种鸭子,在做飞行时会表现不同,有的能飞很高,有的不会飞,而有些又飞的很低。
针对上面的场景,在没有使用策略模式时一般的处理方法是,1.做个超类,行为代码写在超类里面,子类来复用超类的行为或者重写超类的代码;2.继承某个接口,由子类来实现该行为。
传统做法的弊端:
1. 超类的行为不能很好的预测到子类,比如超类A有两个子类,分别为a、b;当前情况下A的行为可以满足当前子类的行为。当后续系统扩充时,新补充进子类c,而c的该项行为不同于子类a、b;则当前需要自己重写超类的方法。这还不是最糟糕的情形,如果需求继续变更,新加入了子类d、e、f、……;这些子类有些与超类相同,有些与c相同,当前情况下将存在许多冗余代码(如与c行为相同的兄弟类会有同样代码的一份拷贝)。子类的行为依赖于实现。
2. 继承于某接口实现的方法弊端和超类的情况类似,同样子类的行为依赖于实现。
出现该弊端的根本原因在于:针对实现编程而不是针对接口编程,实现依赖于代码而不是接口。
策略模式的做法:
1. 封装变化,把行为(X)封装到接口(I)里,尤其是子类执行某行为具有各种的表现形式时,我们把这些不同的表现形式单独做成多个类,让他们去实现接口,每个子类只负责自己行为的具体实现。
2. 在超类中,定义一个接口I变量,类型为保护类型或公共类型。然后在该类实现行为X(通过去调用接口I里的方法);在子类中,构造函数中去实例化不同行为的具体类。
3. 当需求变化时,比如新增加了子类,首先去查看该子类的行为是否不同于已经定义好的行为,如果相同则只需要在该子类的构造函数中实例化具体行为类,如果不同,则需要继续扩充行为类,按照新的行为方式去编码。
策略模式的优点:
1. 行为代码被有效利用,没有冗余代码。
2. 新的需求变化,不会去修改原有代码(隔离变化),只会在原有代码的基础上继续添加。
3. 行为和具体的对象完全分离开,可以有效复用行为代码。比如某种情形下,鸭子和鸡会公用某一种飞行行为,而那种飞行行为是扩展鸭子的飞行类时的编码。这样一来,有了甩掉了继承带来的包袱。
策略模式可以应用的场景举例:
1. 一套ERP系统,用户有许多种,比如财务部门、物流部门、人事部门、管理层等等。出于简单化原则,系统按照职能对每个部门的员工定制了登陆后的主页,员工登陆后,跳转到不同主页。
2. 游戏中,双方采用不同的角色对抗,同样的动作(比如踢腿),不同角色表现出不同的情形:有的原地踢腿,有的跳起来踢,还有向前跑着踢,……
strategyDuck中的类图