《Java 策略模式:代码示例多多,幽默解读》

202 阅读7分钟

一、游戏角色技能释放策略

  1. 策略模式引入背景
    在一个奇幻角色扮演游戏里,游戏角色拥有多样技能,像英勇战士的 “强力斩击”“盾牌格挡”,敏捷刺客的 “隐匿突袭”“飞刀绝技”,神秘法师的 “火焰冲击”“冰霜禁锢”。若用传统写法,在角色类的技能释放方法中,会充斥大量 if - else 判断,例如:

class GameCharacter {
    String characterType;

    void releaseSkill() {
        if ("Warrior".equals(characterType)) {
            if ("强力斩击".equals(skillName)) {
                // 执行战士强力斩击逻辑,如挥剑造成高额伤害,有特殊动画效果
                System.out.println("战士挥出强力一剑,造成巨额伤害!");
            } else if ("盾牌格挡".equals(skillName)) {
                // 举起盾牌,降低所受伤害,改变角色防御姿态
                System.out.println("战士举起盾牌,坚如磐石,格挡攻击!");
            }
        } else if ("Assassin".equals(characterType)) {
            // 刺客技能判断及执行逻辑类似,十分繁琐冗长
            //...
        } else if ("Mage".equals(characterType)) {
            // 法师技能判断及执行逻辑类似,代码不断堆砌
            //...
        }
    }
}

这种结构随着技能和角色类型增多,代码极难维护与扩展。

  1. 策略模式应用

    • 策略接口定义:先创建 SkillReleaseStrategy 接口,规范技能释放行为。

interface SkillReleaseStrategy {
    void release();
}
  • 具体策略类实现

    • 战士强力斩击策略类

class WarriorPowerSlashStrategy implements SkillReleaseStrategy {
    @Override
    public void release() {
        System.out.println("战士紧握巨剑,凝聚全身力量,向前猛力挥出,剑刃划过空气,造成 500 点伤害,触发炫酷斩击特效!");
    }
}
  • 战士盾牌格挡策略类

class WarriorShieldBlockStrategy implements SkillReleaseStrategy {
    @Override
    public void release() {
        System.out.println("战士迅速将盾牌立于身前,盾牌泛起微光,吸收 80%的外来伤害,自身进入防御强化状态。");
    }
}
  • 刺客隐匿突袭策略类

class AssassinStealthStrikeStrategy implements SkillReleaseStrategy {
    @Override
    public void release() {
        System.out.println("刺客隐身潜入敌阵,瞬间现身,从敌人背后发动致命一击,造成 400 点暴击伤害,附带流血效果。");
    }
}
  • 上下文类设置:游戏角色类作为上下文,持有策略接口引用,灵活切换策略。
class GameCharacter {
    private SkillReleaseStrategy skillReleaseStrategy;

    public GameCharacter(SkillReleaseStrategy skillReleaseStrategy) {
        this.skillReleaseStrategy = skillReleaseStrategy;
    }

    public void setSkillReleaseStrategy(SkillReleaseStrategy skillReleaseStrategy) {
        this.skillReleaseStrategy = skillReleaseStrategy;
    }

    public void releaseSkill() {
        skillReleaseStrategy.release();
    }
}
  1. 使用示例
public class Game {
    public static void main(String[] args) {
        // 创建战士角色并设置强力斩击策略
        GameCharacter warrior = new GameCharacter(new WarriorPowerSlashStrategy());
        warrior.releaseSkill();

        // 切换为盾牌格挡策略
        warrior.setSkillReleaseStrategy(new WarriorShieldBlockStrategy());
        warrior.releaseSkill();

        // 创建刺客角色并释放隐匿突袭技能
        GameCharacter assassin = new GameCharacter(new AssassinStealthStrikeStrategy());
        assassin.releaseSkill();
    }
}

二、电商商品促销定价策略

  1. 策略模式引入背景
    电商平台的商品定价在促销期间复杂多变,日常按原价销售,到促销季,有满减(如满 200 减 50)、折扣(打 8 折)、赠品(买一送一)等多种策略。传统编码在计算商品最终价格方法里,满是 if - else 区分促销类型。
class Product {
    String promotionType;
    double originalPrice;

    double calculateFinalPrice() {
        if ("满减".equals(promotionType)) {
            // 满减逻辑,判断金额是否达标,计算减免后价格
            //...
        } else if ("折扣".equals(promotionType)) {
            // 折扣逻辑,按比例计算折后价
            //...
        } else if ("赠品".equals(promotionType)) {
            // 赠品价值评估及价格处理逻辑
            //...
        }
        return originalPrice;
    }
}

新增促销策略就得反复修改该方法,易出错且难维护。

  1. 策略模式应用

    • 策略接口定义:定义 PromotionPricingStrategy 接口。
interface PromotionPricingStrategy {
    double calculatePrice(double originalPrice);
}
  • 具体策略类实现

    • 满减策略类
class FullReductionStrategy implements PromotionPricingStrategy {
    private final int fullAmount;
    private final int reductionAmount;

    public FullReductionStrategy(int fullAmount, int reductionAmount) {
        this.fullAmount = fullAmount;
        this.reductionAmount = reductionAmount;
    }

    @Override
    public double calculatePrice(double originalPrice) {
        if (originalPrice >= fullAmount) {
            return originalPrice - reductionAmount;
        }
        return originalPrice;
    }
}
  • 折扣策略类
class DiscountStrategy implements PromotionPricingStrategy {
    private final double discountRate;

    public DiscountStrategy(double discountRate) {
        this.discountRate = discountRate;
    }

    @Override
    public double calculatePrice(double originalPrice) {
        return originalPrice * discountRate;
    }
}
  • 赠品策略类:为简化示例,赠品策略暂按赠品价值占商品价值一定比例估算对价格影响(实际可复杂得多)。

class GiftStrategy implements PromotionPricingStrategy {
    private final double giftValueRate;

    public GiftStrategy(double giftValueRate) {
        this.giftValueRate = giftValueRate;
    }

    @Override
    public double calculatePrice(double originalPrice) {
        return originalPrice * (1 - giftValueRate);
    }
}
  • 上下文类设置:商品类作为上下文,关联促销策略。
class Product {
    private PromotionPricingStrategy promotionPricingStrategy;
    private double originalPrice;

    public Product(PromotionPricingStrategy promotionPricingStrategy, double originalPrice) {
        this.promotionPricingStrategy = promotionPricingStrategy;
        this.originalPrice = originalPrice;
    }

    public void setPromotionPricingStrategy(PromotionPricingStrategy promotionPricingStrategy) {
        this.promotionPricingStrategy = promotionPricingStrategy;
    }

    public double calculateFinalPrice() {
        return promotionPricingStrategy.calculatePrice(originalPrice);
    }
}
  1. 使用示例
public class ECommerce {
    public static void main(String[] args) {
        // 商品原价 300,使用满减策略(满 200 减 50)
        Product product1 = new Product(new FullReductionStrategy(200, 50), 300);
        System.out.println("满减后价格: " + product1.calculateFinalPrice());

        // 商品原价 250,使用折扣策略(8 折)
        Product product2 = new Product(new DiscountStrategy(0.8), 250);
        System.out.println("折扣后价格: " + product2.calculateFinalPrice());

        // 商品原价 100,使用赠品策略(赠品价值占商品 20%)
        Product product3 = new Product(new GiftStrategy(0.2), 100);
        System.out.println("考虑赠品后价格: " + product3.calculateFinalPrice());
    }
}

三、图形绘制形状绘制策略

  1. 策略模式引入背景
    图形绘制软件要绘制多种形状,像矩形、圆形、三角形等,若用常规单一方法处理,代码会这样:
class GraphicsDrawer {
    String shapeType;

    void draw() {
        if ("矩形".equals(shapeType)) {
            // 绘制矩形逻辑,确定四个顶点坐标,连线成矩形
            //...
        } else if ("圆形".equals(shapeType)) {
            // 绘制圆形逻辑,以圆心和半径画圆
            //...
        } else if ("三角形".equals(shapeType)) {
            // 绘制三角形逻辑,确定三个顶点坐标,连线成三角形
            //...
        }
    }
}

每新增形状,就要在 draw 方法里加大量新逻辑,导致代码臃肿杂乱。

  1. 策略模式应用

    • 策略接口定义:定义 ShapeDrawingStrategy 接口。
interface ShapeDrawingStrategy {
    void drawShape();
}
  • 具体策略类实现

    • 矩形绘制策略类
class RectangleDrawingStrategy implements ShapeDrawingStrategy {
    @Override
    public void drawShape() {
        System.out.println("确定矩形左上角坐标 (x1,y1) 和右下角坐标 (x2,y2),依次连接 (x1,y1)、(x2,y1)、(x2,y2)、(x1,y2) 四点,绘制出矩形。");
    }
}
  • 圆形绘制策略类
class CircleDrawingStrategy implements ShapeDrawingStrategy {
    @Override
    public void drawShape() {
        System.out.println("以给定圆心坐标 (x0,y0) 和半径 r,利用数学公式,围绕圆心绘制圆周,形成圆形。");
    }
}
  • 三角形绘制策略类
class TriangleDrawingStrategy implements ShapeDrawingStrategy {
    @Override
    public void drawShape() {
        System.out.println("确定三角形三个顶点坐标 (x1,y1)、(x2,y2)、(x3,y3),依次连接三点,绘制出三角形。");
    }
}
  • 上下文类设置:绘图类作为上下文,管理绘制策略。
class GraphicsDrawer {
    private ShapeDrawingStrategy shapeDrawingStrategy;

    public GraphicsDrawer(ShapeDrawingStrategy shapeDrawingStrategy) {
        this.shapeDrawingStrategy = shapeDrawingStrategy;
    }

    public void setShapeDrawingStrategy(ShapeDrawingStrategy shapeDrawingStrategy) {
        this.shapeDrawingStrategy = shapeDrawingStrategy;
    }

    public void draw() {
        shapeDrawingStrategy.drawShape();
    }
}
  1. 使用示例
public class GraphicsApp {
    public static void main(String[] args) {
        // 绘制矩形
        GraphicsDrawer drawer1 = new GraphicsDrawer(new RectangleDrawingStrategy());
        drawer1.draw();

        // 绘制圆形
        GraphicsDrawer drawer2 = new GraphicsDrawer(new CircleDrawingStrategy());
        drawer2.draw();

        // 绘制三角形
        GraphicsDrawer drawer3 = new GraphicsDrawer(new TriangleDrawingStrategy());
        drawer3.draw();
    }
}

四、文件加密解密策略

  1. 策略模式引入背景
    文件处理工具常需加密解密操作,支持多种算法,如对称加密的 AES、DES,非对称加密的 RSA。传统做法在加密解密方法里,靠 if - else 区分算法。
class FileProcessor {
    String encryptionAlgorithm;
    byte[] fileData;

    byte[] processFile() {
        if ("AES".equals(encryptionAlgorithm)) {
            // AES 加密解密逻辑,加载密钥,调用加密库方法
            //...
        } else if ("DES".equals(encryptionAlgorithm)) {
            // DES 加密解密逻辑,类似操作,不同算法参数
            //...
        } else if ("RSA".equals(encryptionAlgorithm)) {
            // RSA 加密解密逻辑,公私钥处理等复杂步骤
            //...
        }
        return fileData;
    }
}

切换或新增算法,代码修改麻烦,维护困难。

  1. 策略模式应用

    • 策略接口定义:定义 FileEncryptionStrategy 接口。
interface FileEncryptionStrategy {
    byte[] process(byte[] fileData);
}
  • 具体策略类实现

    • AES 加密策略类:假设已引入对应加密库,简化展示核心逻辑。
class AesEncryptionStrategy implements FileEncryptionStrategy {
    private final byte[] key;

    public AesEncryptionStrategy(byte[] key) {
        this.key = key;
    }

    @Override
    public byte[] process(byte[] fileData) {
        // 利用 AES 算法和密钥对文件数据加密,返回加密后数据
        System.out.println("使用 AES 算法和给定密钥对文件数据进行加密操作。");
        return encryptedData;
    }
}
  • DES 加密策略类
class DesEncryptionStrategy implements FileEncryptionStrategy {
    private final byte[] key;

    public DesEncryptionStrategy(byte[] key) {
        this.key = key;
    }

    @Override
    public byte[] process(byte[] fileData) {
        // DES 加密操作,类似 AES,按自身算法规则处理
        System.out.println("利用 DES 算法与密钥加密文件数据。");
        return encryptedData;
    }
}
  • RSA 加密策略类
class RsaEncryptionStrategy implements FileEncryptionStrategy {
    private final byte[] publicKey;

    public RsaEncryptionStrategy(byte[] publicKey) {
        this.publicKey = publicKey;
    }

    @Override
    public byte[] process(byte[] fileData) {
        // 使用 RSA 公钥加密数据,适配公钥加密流程
        System.out.println("凭借 RSA 公钥对文件数据开展加密处理。");
        return encryptedData;
    }
}
  • 上下文类设置:文件处理器类作为上下文,操控加密策略。

class FileProcessor {
    private FileEncryptionStrategy fileEncryptionStrategy;
    private byte[] fileData;

    public FileProcessor(FileEncryptionStrategy fileEncryptionStrategy, byte[] fileData) {
        this.fileEncryptionStrategy = fileEncryptionStrategy;
        this.fileData = fileData;
    }

    public void setFileEncryptionStrategy(FileEncryptionStrategy fileEncryptionStrategy) {
        this.fileEncryptionStrategy = fileEncryptionStrategy;
    }

    public byte[] processFile() {
        return fileEncryptionStrategy.process(fileData);
    }
}
  1. 使用示例
public class FileTool {
    public static void main(String[] args) {
        byte[] sampleData = "这是一段示例文件数据".getBytes();
        // 使用 AES 加密
        byte[] aesKey = generateAesKey(); // 假设存在生成密钥方法
        FileProcessor processor1 = new FileProcessor(new AesEncryptionStrategy(aesKey), sampleData);
        byte[] encryptedData1 = processor1.processFile();
        System.out.println("AES 加密后数据: " + Arrays.toString(encryptedData1));

        // 使用 DES 加密
        byte[] desKey = generateDesKey();
        FileProcessor processor2 = new FileProcessor(new DesEncryptionStrategy(desKey), sampleData);
        byte[] encryptedData2 = processor2.processFile();
        System.out.println("DES 加密后数据: " + Arrays.toString(encryptedData2));

        // 使用 RSA 加密
        byte[] rsaPublicKey = getRsaPublicKey();
        FileProcessor processor3 = new FileProcessor(new RsaEncryptionStrategy(rsaPublicKey), sampleData);
        byte[] encryptedData3 = processor3.processFile();
        System.out.println("RSA 加密后数据: " + Arrays.toString(encryptedData3));
    }
}

通过这些丰富多样且带详细代码的示例,能清晰看到策略模式在不同场景下将复杂逻辑拆解、提升代码可维护与扩展性的强大优势。