2025年[设计模式学习笔记] -- 策略模式

[设计模式学习笔记] -- 策略模式策略模式 定义了算法族 分别封装起来 让他们之间可以互相替换 此模式让算法的变化独立于使用算法的客户 举一个简单的例子来描述策略模式 设计一款冷兵器时代士兵打仗的游戏 游戏内部设计要使用 OO 技术 首先 设计一个士兵对象 Soilder 作为父类

大家好,我是讯享网,很高兴认识大家。

策略模式

定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

  举一个简单的例子来描述策略模式。

  设计一款冷兵器时代士兵打仗的游戏,游戏内部设计要使用OO技术。

  首先,设计一个士兵对象(Soilder)作为父类,然后在设计许多不同种类的士兵对象来继承士兵这个父类,比如:长枪兵(Spearman)、骑兵(Cavalryman)、弓箭手(Bowman)等等,设计好后进行讨论,觉得不错没有问题,可以开始开发,测试,游戏公测……一切都不错,具体如下面的类图所示:

  
讯享网

  在游戏运营了一段时候之后,发现需要一些新元素来吸引玩家,要求不同种类的士兵的攻击动作不同,并且要求士兵需要有游泳、攀爬等技能。使用OO技术非常好解决啊,打开类的设计图开始干活吧!可以把hit方法设计成抽象方法,让每种士兵都实现自己的hit,然后在Soilder类中加入游泳,攀爬的方法,修改的类图如下:

  

  使用这种设计方式后,在游戏运行的过程中我们会看到,骑兵骑着马在爬树。显然的,在设计的时候忽略了一点,并非所有的士兵都可以游泳和攀爬。有许多不可做这些行为的士兵,对代码的局部修改,影响的层面可不仅是局部。

  使用继承如何?

  把swim和clmb放到子类中,覆盖掉父类的对应方法,像hit的做法一样。可如果以后要加入其他类型的士兵又会如何?比如重甲步兵没办法游泳也没办法攀爬,因为重甲太重了,而骑兵则无法骑着马攀爬,但可以骑着马过河等等。可见利用继承来提供士兵的行为会造成:

  1.代码在多个子类中重复;

  2.运行时的行为不容易改变;

  3.很难知道所有士兵的全部行为;

  4.改变会牵一发而动全身,造成其他某些类型的士兵不想要的行为;

  利用接口如何?

  可以加入ISwin和IClimb接口,把swim函数和climb函数从父类中取出来,并被子类实现,如下图所示:

  

  但士兵的规格会常常改变,每当有新的士兵类型出现,就要被迫检查兵可能需要实现ISwim和IClimb接口。并且这么以来重复的代码会变多,因为实现的可以游泳和爬树的代码是一样的。比如有一天swim的方式发生了变化,现有的50个士兵子类都需要修改swim函数,这是不可以接受的。

  如何解决?

  可以看出,并非所有的子类都会游泳和爬树,所以继承并不是适当的解决方式。虽然使用接口可以解决一部分问题,但是却造成了代码无法复用,幸运的是,有一个原则恰好用于此处。

设计原则1

找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

  也就是说,每次需求一来,都会使某些方面的代码发生变化,那么基本可以确定这部分代码需要被抽出来和其他稳定的代码有所区分。

  现在,为了要分开变化和不会变化的部分,我们准备建立两组类,一个是swim相关的,一个是clmb相关的,并且要做到一切能有弹性,正因为一开始设计的行为没有弹性才导致种种问题。比方说,我要产生一个新的类型的轻甲士兵,并指定行为攀爬给他,也就是说在士兵类中包涵设置行为的方法,这样就可以在运行时动态改变行为,有了这些目标要实现,就引出了第二个设计原则。

设计原则2

针对接口或抽象类编程,而不是针对实现编程。

  我们利用接口代表每个行为(Behavior),比方说SwimBehavior和ClimbBehavior,而行为的每个实现都将实现其中的一个接口。Soilder类不会负责实现它们,反而是由一组其他类专门去实现,并整合到Soilder类中,具体的做法是在Soilder类中加入两个实例变量,分别为SwimBehavior和ClimbBehavior,声明为接口类型,每个士兵子类都会动态的设置这些变量在运行时引用正确的行为类型。看一下类图与实现的代码(Java代码)。

  

  

package cn.net.bysoft.Strategy; // 士兵 public abstract class Soldier { // 士兵的名字 private String name; private SwimBehavior swimBehavior; private ClimbBehavior climbBehavior; public Soldier() { super(); } public Soldier(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public SwimBehavior getSwimBehavior() { return swimBehavior; } public void setSwimBehavior(SwimBehavior swimBehavior) { this.swimBehavior = swimBehavior; } public ClimbBehavior getClimbBehavior() { return climbBehavior; } public void setClimbBehavior(ClimbBehavior climbBehavior) { this.climbBehavior = climbBehavior; } // 显示士兵的信息 public void display() { System.out.println("这个士兵的名字:" + name); } // 士兵攻击敌人。 public abstract void hit(); // 委托给行为去处理。 public void swim() { swimBehavior.swim(); } public void climb() { climbBehavior.climb(); } }

讯享网
小讯
上一篇 2025-01-24 19:14
下一篇 2025-02-23 14:19

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/65919.html