设计模式(一)—— 策略模式

忘是亡心i 2022-05-20 05:06 265阅读 0赞

由于之前看的容易忘记,因此特记录下来,以便学习总结与更好理解,该系列博文也是第一次记录,所有有好多不完善之处请见谅与留言指出,如果有幸大家看到该博文,希望报以参考目的看浏览,如有错误之处,谢谢大家指出与留言。

思路:

1、模拟鸭子项目

2、项目的新需求

3、用OO原则解决新需求的不足

4、用策略模式来新需求解决

5、重新设计模拟鸭子项目

6、总结策略模式定义

一、模拟鸭子项目

  1. 1、从项目"模拟鸭子游戏"开始 2、从OO的角度设计这个项目,鸭子超类,扩展超类:
  2. public abstract class Duck {
  3. public void Quack() {
  4. System.out.println("~~gaga~~");
  5. }
  6. public abstract void display();
  7. public void swim() {
  8. System.out.println("~~im swim~~");
  9. }
  10. }1GreenHeadDuck继承Duck
  11. public class GreenHeadDuck extends Duck {
  12. @Override
  13. public void display() {
  14. System.out.println("**GreenHead**");
  15. }
  16. }
  17. 2、同理可有RedHeadDuck

二、项目的新需求

  1. 1、应对新的需求,看看这个设计的可扩展性 1)添加会飞的鸭子 2OO思维里的继承方式解决方案是:
  2. public abstract class Duck {
  3. ...;
  4. public void Fly() {
  5. System.out.println("~~im fly~~");
  6. }
  7. };

问题来了,这个Fly让所有子类都会飞了,这是不科学的。继承的问题:对类的局部改动,尤其超类的局部改动,会影响其他部分。影响会有溢出效应

三、用OO原则解决新需求的不足

  1. 1、继续尝试用OO原理来解决,覆盖:
  2. public class GreenHeadDuck extends Duck {
  3. ...;
  4. public void Fly() {
  5. System.out.println("~~no fly~~");//把会飞的工程覆盖掉,实现不让他飞。}
  6. }
  7. 这个导致,后面几十个鸭子不没有这个功能,不会飞,那么他们的都要去实现。工作量大,而且重复劳动。有人说:会飞功能不放在超类中,放在抽象函数,让子类去实现,这样需要的就去实现,不需要的不需要实现,但是这样,代码复用性却不高,比如:有10种鸭子都会飞,而且飞的方式都一样,所以实现代码都是一样的,代码复用性降低,对某些子类方便,但对其他有些子类确有影响。
  8. 2、又有新需求,石头鸭子,填坑:
  9. public class StoneDuck extends Duck {
  10. .... };比如石头鸭子,既不会飞,也不会叫,那么所有代码都要去覆盖。
  11. 所以:超类挖的一个坑,每个子类都要来填,增加工作量,复杂度O(N^2)。不是好的设计方式

四、用策略模式来新需求解决

策略模式:属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得他们可以相互替换。策略模式使得算法可以在不影响客户端的情况下发生变化。

所以遇到问题首先要分析项目的变化与不变化部分,对项目中的问题都可以按此思路。

需要新的设计方式,应对项目的扩展性,降低复杂度:

1)分析项目变化不变部分,提取变化部分,然后把变化的部分抽象成接口+实现

2)鸭子哪些功能是会根据新需求变化的?叫声、飞行…

  1. 1、接口:
  2. 1public interface FlyBehavior
  3. {
  4. void fly();}
  5. 2public interface QuackBehavior
  6. {
  7. void quack();};
  8. 3)抽象接口好处:新增行为简单,行为类更好的复用,组合更方便。既有继承带来的复用好处,没
  9. 有继承带来的坏处。

五、重新设计模拟鸭子项目

  1. 1、重新设计的鸭子项目:
  2. public abstract class Duck {
  3. FlyBehavior mFlyBehavior;
  4. QuackBehavior mQuackBehavior;
  5. public Duck() { }
  6. public void Fly() {
  7. mFlyBehavior.fly();
  8. }
  9. public void Quack() {
  10. mQuackBehavior.quack();
  11. }
  12. public abstract void display();
  13. }

六、总结策略模式定义

1、绿头鸭、石头鸭:

在超累的基础上,子类直接在构造函数中,去new一个行为族,在用行为族中的行为去实现。

  1. public class GreenHeadDuck extends Duck {
  2. public GreenHeadDuck() {
  3. mFlyBehavior = new GoodFlyBehavior();
  4. mQuackBehavior = new GaGaQuackBehavior();
  5. }
  6. @Override
  7. public void display() {...}
  8. }

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

七、策略模式总结与注意点

1、分析项目中变化部分与不变部分(方法论)——》这个方法论不仅是策略模式中才可以用的,用来分析项目中变法的何不变化的,变化的就可以怎么来抽取替换。而且变化的抽离出来的行为族,行为族之间是可以来相互替换的。

2、多用组合少用继承用行为类组合而不是行为的继承。更有弹性

3、如果找不到适用的模式怎么办?

(1).可能对项目分析的不够透彻。

(2).存在特殊的项目无法用设计模式,那么就只能用原始的面向对象的特性(其实设计模式也是基于oop总结提炼出来的精华所在)

八、策略模式中的设计原则

1、开闭原则(Open-Closed Principle,缩写为OCP)

  1. 1)一个软件实体应当**对扩展****开放**(例如对抽象层的扩展),**对修改****关闭**(例如对抽象层的修改)。即在设计一个模块的时候,应**当使这个模块可以在不被修改的前提下被扩展**。
  2. 2)**开闭原则的关键,在于抽象**。策略模式,是开闭原则的一个极好的应用范例。

2、里氏替换原则(Liskov Substitution Principle,缩写为LSP)

  1. 1)里氏替换原则里一个软件实体如果使用的是**一个基类的话,那么一定适用于其子类**,而且它根本不能察觉到基类对象和子类对象的区别。比如,假设有两个类,一个是Base类,一个是Derived类,并且Derived类是Base类的子类。**那么一个方法如果可以接受一个基类对象b的话:method1(Base b),那么它必然可以接受一个子类对象d,也即可以有method1(d)。反之,则不一定成立**。
  2. 2)**里氏替换原则讲的是基类与子类的关系**。只有当这种关系存在时,里氏替换关系才存在,反之则不存在。
  3. 3)**策略模式之所以可行的基础**便是**里氏替换原则**:策略模式要求所有的**策略对象都是可以互换**的,因此它们都必须是一个抽象策略角色的子类。**在客户端则仅知道抽象策略角色类型,虽然变量的真实类型可以是任何一个具体策略角色的实例。**

九、补充小结

策略模式的重心

策略模式的重心不是如何实现算法而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。而对于在什么情况下使用什么算法,是由客户端决定的。

算法的平等性

策略模式一个很大的特点就是各个策略算法的平等性。对于一系列具体的策略算法,大家的地位是完全一样的,正因为这个平等性,才能实现算法之间可以相互替换。所有的策略算法在实现上也是相互独立的,相互之间是没有依赖的。

所以可以这样描述这一系列策略算法:策略算法是相同行为的不同实现

运行时策略的唯一性

运行期间,策略模式在每一个时刻只能使用一个具体的策略实现对象,虽然可以动态地在不同的策略实现中切换,但是同时只能使用一个。

公有的行为

经常见到的是,所有的具体策略类都有一些公有的行为。这时候,就应当把这些公有的行为放到共同的抽象策略角色QuackBehavior类(该类只是举例这个层面的类)里面。当然这时候抽象策略角色必须要用Java抽象类实现,而不能使用接口。

十、策略模式的缺点

1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道算法或行为的情况

2)由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观

发表评论

表情:
评论列表 (有 0 条评论,265人围观)

还没有评论,来说两句吧...

相关阅读

    相关 设计模式)—— 策略模式

    由于之前看的容易忘记,因此特记录下来,以便学习总结与更好理解,该系列博文也是第一次记录,所有有好多不完善之处请见谅与留言指出,如果有幸大家看到该博文,希望报以参考目的看浏览,如