雍禾植发帝之java设计模式学习(一)策略模式
策略模式
1. 策略模式的基本内容
- 定义:(Strategy Pattern)定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户
- 遇到什么问题时想要使用策略模式:有多个不同的类,它们不同的地方仅是它们的
行为方法
,或者是某些类中,它们的某些行为方法
需要经常的改变,当面向实现编程
时,我们的代码被实现
绑死,所以当改变
来临时(比如你的老板让你修改需求时),我们的工作量是非常巨大的(请参考后面的例子) - 如何解决:将这些经常需要改变的
行为方法
从类中抽离出来,另外形成一组类(暂时将其称为’锦囊’),当原本的类需要某个行为方法
时,则从锦囊
中取出对应的行为方法
给它,当需要更换行为方法
时,则只需要从锦囊
中取出另外一个行为方法
替换就可以达到目的(这样既达到复用
的目的,也不让原本的类被实现
绑死)
2. 策略模式的“由来”
2.1“继承”局限性
场景一:
当小明设计一款冒险游戏时,有三个不同的角色(King、Queen、Knight),每个角色有一个display()
会告诉玩家他们是什么角色,小明理所当然的想到Java基础中的继承
来实现:
场景二:
第二天,游戏策划告诉小明,角色应该可以战斗,小明想这还不简单,只需要在Character抽象类
中添加一个fight()
,然后在每一个角色实现类中实现这个方法,那不就行了吗,说干就干,小明已经想到自己完成之后下班要去吃什么了:(注意:图中fight()
在不同的角色实现中,可能是用不同的武器去战斗,在这里就不画出来了)
场景三:
然而too young too simple,就在小明提交了自己的想法没多久,策划就打来了电话:小明,Queen
王后是不会战斗的,怎么你的王后跟着国王下战场了?!
小明:啊,还有这种情况,不过难不倒我,这很简单,只要在Queen
的实现类中,让fight()
什么都不做,这样王后就不会去战斗了:
场景四:
到了这个时候,小明突然想到,如果过两天策划突然决定添加一个生育系统giveBirth()
,到时候若是在抽象类Character
类添加该功能,那岂不是所有的角色(包括King
和Knight
)都会生小孩了,到时候要避免这种情况,岂不是又要在King
和Knight
的实现类中,覆盖掉giveBirth()
,让它们什么都不做(类似于场景三),想到那样的工作量,小明就隐隐一阵头疼
使用继承来提供Character的行为,会导致以下的缺点
- 代码在多个子类中重复
- 运行时的行为不容易改变
- 很难知道所有角色的全部行为
- 改变会牵一发而动全身,造成其他角色不想要的改变
那要是接口的话呢?:
场景五:
小明将fight()
提取成一个FightBehavior接口
,当以后新增加的角色会战斗时,则实现该接口,若不会战斗时,就不实现该接口,如下图中的王后,这样总算可以解决刚刚的问题了吧。
其实这样又出现了新的问题:虽然解决了一部分的问题,却造成代码无法“复用”的问题(当不同的角色使用相同的方式战斗时,fight()
需要在不同的实现类中实现多次。而且当这个方法发生改变时,修改起来的代码量是很多),有没有什么办法,既可以提高代码“复用”率,并且当需求改变时,可以用最小的代码量修改就达成目标呢?
2.2 “策略模式”登场
将经常需要改变的行为方法从类中抽离出来,另外形成一组类(暂时将其称为’锦囊’),当原本的类需要某个行为方法时,则从锦囊中取出对应的行为方法给它,当需要更换行为方法时,则只需要从锦囊中取出另外一个行为方法替换就可以达到目的(这样既达到复用的目的,也不让原本的类被实现绑死)
这句话的意思有点抽象,让我们代入到小明的开发场景中去:
既然fight()
战斗这个行为方法常常需要改变,干脆把它从具体的类实现中抽离出来,将各种武器(Knife、Sword、Arrow,同时也有’空武器’)放入一个战斗锦囊,然后给每一个角色发放一个战斗锦囊,当角色需要某一个武器时,则从锦囊中取出相应的武器就好了
- 只有
Character类
实现了fight()
方法,这个方法让角色使用武器锦囊
- 此处每一个角色都继承了来自父类的
WeaponBehavior wb;
,并且在构造函数处将对应的武器实现类new
给wb
2.3 “策略模式”中的设计原则
- 而在“策略模式”中,我们强调将经常发生改变的行为方法从类中抽离出来,这一步就是体现了设计原则中的"封装变化"
- 在具体的角色类中,角色只需要知道调用行为方法的接口,而不需要管该方法的具体实现,而这体现的就是设计原则中的"接口编程"
- 将原本的类和封装变化而产生的类二者相结合起来使用,这就是“组合”,体现了设计原则中的"多用组合,少用继承
策略模式的介绍就到这里!
####此处粘上来代码(其中角色类和武器类分别只贴上来一个)
//Character类(抽象类)
public abstract class Character {
WeaponBehavior wb;
public abstract void display();
public void fight() {
wb.userWeapon();
}
}
//King类(继承自Character类)
public class King extends Character {
public King() {
wb = new SwordBehavior(); //在此处修改角色对应的战斗方式:此处让他从武器锦囊中取出 “剑”
}
@Override
public void display() {
System.out.println("我是国王");
}
}
//武器锦囊接口
public interface WeaponBehavior {
public void userWeapon();
}
//武器:剑(实现了接口 'WeaponBehavior')
public class SwordBehavior implements WeaponBehavior{
@Override
public void userWeapon() {
System.out.println("使用 剑 攻击!");
}
}
//测试类
public class CharacterGame {
public static void main(String args[]) {
Character king = new King();
king.display();
king.fight();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47