2021年10月8日-设计模式之策略模式

第二十三章:策略模式

一、情景引入

现在我们要做一个 rpg 游戏,rpg 游戏有多种职业,这些职业的行为会有所不同。请看下述方式实现各个职业有什么问题:

角色抽象类:

abstract public class Character {
    public abstract void display();

    public abstract void attack();

    public abstract void cure();

    public void flee() {
        System.out.println("正在撤离");
    }
}

具体角色类:

  • 战士类
public class Warrior extends Character {
    @Override
    public void display() {
        System.out.println("战士角色");
    }

    @Override
    public void attack() {
        System.out.println("使用物理攻击进行普攻");
    }

    @Override
    public void cure() {
        System.out.println("使用血瓶恢复 HP");
    }
}
  • 法师类
public class Witcher extends Character {
    @Override
    public void display() {
        System.out.println("法师角色");
    }

    @Override
    public void attack() {
        System.out.println("使用魔法攻击普攻");
    }

    @Override
    public void cure() {
        System.out.println("使用治愈魔法恢复 HP");
    }
}

根据职业不同,我们有不同的具体实现。不过,法师就不能喝药回复 HP?战士就不能使用魔法攻击?

为了让战士可以使用魔法攻击,我们是否需要再写个子类继承战士类,然后重写 attack 方法?

可以发现像 attack 和 cure 这种方法应该是可变的,通过继承实现是不合理的

二、模式简介

在这里插入图片描述

  • StrategyA、StrategyB 策略接口
  • ConcreteStrategy 根据不同的情形有不同的策略实现
  • 通过聚合的方式动态的在 Subject 中更新策略

三、模式应用

在这里插入图片描述

攻击策略接口

public interface AttackStrategy {
    void attack();
}

具体的攻击策略

public class MagicalAttack implements AttackStrategy{
    @Override
    public void attack() {
        System.out.println("使用魔法攻击进行普攻");
    }
}
public class PhysicalAttack implements AttackStrategy {
    @Override
    public void attack() {
        System.out.println("使用物理攻击进行普攻");
    }
}

治疗策略接口

public interface CureStrategy {
    void cure();
}

具体的治疗策略

public class MagicalCure implements CureStrategy {
    @Override
    public void cure() {
        System.out.println("使用治愈魔法恢复 HP");
    }
}
public class MedcineCure implements CureStrategy{

    @Override
    public void cure() {
        System.out.println("使用血瓶恢复 HP");
    }
}

角色抽象类

abstract public class Character {
    private AttackStrategy attackStrategy;
    private CureStrategy cureStrategy;

    public void setAttackStrategy(AttackStrategy attackStrategy) {
        this.attackStrategy = attackStrategy;
    }

    public void setCureStrategy(CureStrategy cureStrategy) {
        this.cureStrategy = cureStrategy;
    }

    public abstract void display();

    public void attack() {
        if (attackStrategy != null) {
            attackStrategy.attack();
        }
    }

    public void cure() {
        if (cureStrategy != null) {
            cureStrategy.cure();
        }
    }

    public void flee() {
        System.out.println("正在撤离");
    }
}

战士类

public class Warrior extends Character {
    @Override
    public void display() {
        System.out.println("战士角色");
    }
}

法师类

public class Witcher extends Character {
    @Override
    public void display() {
        System.out.println("法师角色");
    }
}

具体策略对象有一份就行了,使用享元模式

public class StrategyFactory {
    private Map<String, AttackStrategy> attackStrategies;
    private Map<String, CureStrategy> cureStrategies;

    public StrategyFactory() {
        this.attackStrategies = new HashMap<>(2);
        this.cureStrategies = new HashMap<>(2);
    }

    public AttackStrategy getAttackStrategy(String type) {
        AttackStrategy strategy = attackStrategies.get(type);
        if (strategy == null) {
            switch (type) {
                case "物理攻击":
                    strategy = new PhysicalAttack();
                    break;
                case "魔法攻击":
                    strategy = new MagicalAttack();
                    break;
            }
            attackStrategies.put(type, strategy);
        }
        return strategy;
    }

    public CureStrategy getCureStrategy(String type) {
        CureStrategy strategy = cureStrategies.get(type);
        if (strategy == null) {
            switch (type) {
                case "药物治疗":
                    strategy = new MedcineCure();
                    break;
                case "魔法治疗":
                    strategy = new MagicalCure();
                    break;
            }
            cureStrategies.put(type, strategy);
        }
        return strategy;
    }
}

测试类

public class StrategyTest {
    public static void main(String[] args) {
        StrategyFactory strategyFactory = new StrategyFactory();
        Witcher witcher = new Witcher();

        witcher.setAttackStrategy(strategyFactory.getAttackStrategy("物理攻击"));
        witcher.setCureStrategy(strategyFactory.getCureStrategy("魔法治疗"));
        witcher.attack();
        witcher.cure();
        System.out.println("=== 改变策略 ===");
        witcher.setAttackStrategy(strategyFactory.getAttackStrategy("魔法攻击"));
        witcher.setCureStrategy(strategyFactory.getCureStrategy("药物治疗"));
        witcher.attack();
        witcher.cure();
    }
}


/**********
使用物理攻击进行普攻
使用治愈魔法恢复 HP
=== 改变策略 ===
使用魔法攻击进行普攻
使用血瓶恢复 HP
**********/

四、模式总结

1)分析类中的可变部分和不变部分,可变部分做成策略簇

2)体现了多用组合聚合,少用继承实现

3)对象增加行为只需要添加一种策略,符合开闭原则

4)不过策略类可能会发生类膨胀

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值