更多关于设计模式的文章请点击:设计模式总结
一、进一步的改进
上面的动物园例子似乎已经足够地完善了,但是仔细想想并不是这样:当另一个SmallDog
被创建时,它实现了BarkBehavior
接口,但是它需要在自身的代码中去重写这个bark()
方法,这个bark()
方法的具体实现暴露在了SmallDog
类中,当我们需要修改SmallDog
的bark()
方法实现时,我们需要在这个类中去修改代码,这就造成了硬编码问题,那么应该怎么解决呢?
这里引申出策略模式
的一个重要思想:使用组合,而不是实现
- BigDogBark实现类
/**
* @Auther: ARong
* @Date: 2018/11/17 23:10
* @Description:
*/
public class BigDogBark implements BarkBehavior {
@Override
public void bark() {
System.out.println("Big Dog 汪汪汪...");
}
}
- BigDog可修改为
/**
* @Auther: ARong
* @Date: 2018/11/17 11:09
* @Description: com.iteason.Animal.BigDog 继承 Animal的所有属性和方法并实现BarkBehavior
*/
public class BigDog extends Animal {
private BarkBehavior barkBehavior;
//构造方法
public BigDog(String name) {
super(name);
//在运行时将BigDogBark向上转型为BarkBehavior
barkBehavior = new BigDogBark();
}
public BigDog() {
}
//将bark()方法的具体实现委托给BarkBehavior的子类
public void performBark(){
barkBehavior.bark();
}
public BarkBehavior getBarkBehavior() {
return barkBehavior;
}
public void setBarkBehavior(BarkBehavior barkBehavior) {
this.barkBehavior = barkBehavior;
}
}
BigDog
类中组合了一个BarkBehavior
的接口,在构造方法中新建一个BarkBehavior
的实现类BigDogBark
,通过面向对象的特征:多态
,在运行时确定由谁实现了BarkBehavior
接口,并且将执行动作委托给了performBark()
方法去调用barkBehavior.bark()
,这就是一个简单的策略模式的应用了。
以上关系可用UML关系图来表达:
二、用策略模式组织类关系实例
在下面,你将看到一堆杂乱的类与接口,这是取自一个动作冒险游戏。你将看到代
表游戏角色的类,以及武器行为的类。每个角色一次只能使用一个武器,但是可以
在游戏的过程中换武器。你的工作是要弄清楚这一切…
这是HeadFirst设计模式中的一个问题,可以使用策略模式,画出一个UML图来表示他们的关系:用Character作为角色的超类,里边含有角色的共同属性以及可变的战斗武器接口、战斗模式接口对象;FightBehavior是战斗模式的接口,Quene和Random分别实现了队列战斗模式和随机战斗模式;WeaponBehavior是战斗武器接口,KnifeBehavior和GanBehavior分别是使用剑、枪作为武器。
* Character超类
/**
* @Auther: ARong
* @Date: 2018/11/17 16:35
* @Description: 角色超类,定义了角色的名字和武器使用方式以及战斗行为
*/
public abstract class Character {
//角色名字
private String name;
//武器使用方式
private WeaponBehavior weaponBehavior;
//战斗行为
private FightBehavior fightBehavior;
//构造方法
public Character(String name) {
this.name = name;
}
public Character() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public WeaponBehavior getWeaponBehavior() {
return weaponBehavior;
}
public void setWeaponBehavior(WeaponBehavior weaponBehavior) {
this.weaponBehavior = weaponBehavior;
}
public FightBehavior getFightBehavior() {
return fightBehavior;
}
public void setFightBehavior(FightBehavior fightBehavior) {
this.fightBehavior = fightBehavior;
}
}
- WeaponBehavior接口
/**
* @Auther: ARong
* @Date: 2018/11/17 16:37
* @Description: 定义了角色的武器使用方式
*/
public interface WeaponBehavior {
public void userWeapon();
}
- FightBehavior接口
/**
* @Auther: ARong
* @Date: 2018/11/17 16:38
* @Description: 定义了角色的战斗行为
*/
public interface FightBehavior {
public void fight();
}
- KnifeBehavior实现类
/**
* @Auther: ARong
* @Date: 2018/11/17 16:42
* @Description: WeaponBehavior的实现类,使用剑作为武器
*/
public class KnifeBehavior implements WeaponBehavior{
@Override
public void userWeapon() {
System.out.println("使用剑战斗");
}
}
- GanBehavior实现类
/**
* @Auther: ARong
* @Date: 2018/11/17 16:43
* @Description: WeaponBehavior的实现类,使用枪作为武器
*/
public class GanBehavior implements WeaponBehavior{
@Override
public void userWeapon() {
System.out.println("使用枪战斗");
}
}
- Quene实现类
/**
* @Auther: ARong
* @Date: 2018/11/17 16:40
* @Description: FightBehavior的实现类,使用队列战斗行为
*/
public class Quene implements FightBehavior{
@Override
public void fight() {
System.out.println("队列战斗");
}
}
- Random实现类
/**
* @Auther: ARong
* @Date: 2018/11/17 16:42
* @Description: FightBehavior的实现类,使用随机战斗行为
*/
public class Random implements FightBehavior{
@Override
public void fight() {
System.out.println("随机战斗");
}
}
- GanFighter角色类
/**
* @Auther: ARong
* @Date: 2018/11/17 17:01
* @Description: GanFighter是一个使用枪和随机战斗方式的角色
*/
public class GanFighter extends Character{
//构造方法
public GanFighter(String name){
super.setName(name);
super.setWeaponBehavior(new GanBehavior());
super.setFightBehavior(new Random());
}
public GanFighter(){
}
//使用武器
public void performWeapon(){
super.getWeaponBehavior().userWeapon();
}
//战斗方式
public void performFight(){
super.getFightBehavior().fight();
}
}
GanFight是一个使用枪和随机战斗方式的角色,所以在它的构造方法中,为它的战斗武器和方式接口创建了具体的实现类,使他拥有了以枪为武器和随机战斗的方式。
使用GanFighter类:
@Test
public void userGanFighter(){
GanFighter g_fighter = new GanFighter("G_Fighter");
System.out.println(g_fighter.getName());
g_fighter.performWeapon();
g_fighter.performFight();
}
如果你想让角色能更加地方便创建和使用,可以在使用方法时传递接口实现类的方式,从而达到要求:
/**
* @Auther: ARong
* @Date: 2018/11/17 16:44
* @Description: Fighter类是Character的子类,并且在构造方法中需要实例化WeaponBehavior接口和FightBehavior接口的子类
*/
public class Fighter extends Character{
//构造方法
public Fighter(String n){
//在实例化Fighter时指定Fighter的名字
super.setName(n);
}
public Fighter(){
}
//战斗武器
public void performWeapon(WeaponBehavior w){
super.setWeaponBehavior(w);
super.getWeaponBehavior().userWeapon();
}
//战斗方式
public void performFight(FightBehavior f){
super.setFightBehavior(f);
super.getFightBehavior().fight();
}
}
使用Fighter类去创建一个使用剑和随机战斗方式的角色:
@Test
public void userFighter(){
Fighter ganFighter = new Fighter("剑神");
System.out.println(ganFighter.getName());
//使用剑
ganFighter.performWeapon(new KnifeBehavior());
//随机战斗方式
ganFighter.performFight(new Random());
}
运行结果: