问题:通过策略模式+工厂模式+模板方法模式实现ifelse优化

项目场景:

提示:这里简述项目相关背景:

示例:商城系统有会员系统,不同会员有不同优惠程度,普通会员不优惠;黄金会员打8折;白金会员优惠50元,再打7折;


问题描述

提示:这里描述项目中遇到的问题:

例如:不同会员处理过程中,业务场景复杂,每种会员的业务逻辑很长,不方便维护。

java 复制代码
public static double quote(String type) {
        double score = 1000;
        double res = 0;
        if (type.equals("1")) {
            res = score;
        } else if (type.equals("2")) {
            res = score - 50;
        } else if (type.equals("3")) {
            res = score * 0.8;
        } else if (type.equals("4")) {
            res = (score - 50) * 0.7;
        }
        return res;
 }

原因分析:

提示:这里填写问题的分析:

业务复杂


解决方案:

提示:这里填写该问题的具体解决方案:

java 复制代码
package com.geekmice.springbootmybatiscrud.strategy.third;

import java.math.BigDecimal;


public interface PayStrategy {
    /**
     * 计算费用
     *
     * @param price
     * @date 2025-02-10
     */
    BigDecimal quote(BigDecimal price);
}

具体策略1:非会员,没有优惠

java 复制代码
package com.geekmice.springbootmybatiscrud.strategy.third;

import java.math.BigDecimal;

public class OrdinaryStrategy implements PayStrategy{
    @Override
    public BigDecimal quote(BigDecimal price) {
        return price;
    }
}

具体策略2:黄金会员,打八折

java 复制代码
package com.geekmice.springbootmybatiscrud.strategy.third;

import java.math.BigDecimal;
import java.util.Objects;

public class GoldStrategy implements PayStrategy{
    @Override
    public BigDecimal quote(BigDecimal price) {

        BigDecimal res = price.multiply(new BigDecimal("0.8"));
        return res;
    }
}

具体策略3:白银会员,先优惠50,后打七折

java 复制代码
package com.geekmice.springbootmybatiscrud.strategy.third;

import com.geekmice.springbootmybatiscrud.strategy.first.Strategy;

import java.math.BigDecimal;

public class PlatinumStrategy implements PayStrategy {
    @Override
    public BigDecimal quote(BigDecimal price) {
        BigDecimal res = price.subtract(new BigDecimal("50")).multiply(new BigDecimal("0.7"));
        return res;
    }
}

上下文对象:持有一个Strategy的引用

java 复制代码
package com.geekmice.springbootmybatiscrud.strategy.third;

import java.math.BigDecimal;

/**
 * @author Administrator
 */
public class PayContext {

    private PayStrategy payStrategy;

    public void setStrategy(PayStrategy payStrategy) {
        this.payStrategy = payStrategy;
    }

    public BigDecimal getPrice(BigDecimal price) {
        if (payStrategy != null) {
            return payStrategy.quote(price);
        }
        return null;
    }
}

测试使用

java 复制代码
package com.geekmice.springbootmybatiscrud.strategy.third;

import java.math.BigDecimal;

public class Demo {
    public static void main(String[] args) {
        PayContext payContext = new PayContext();
        OrdinaryStrategy ordinaryStrategy = new OrdinaryStrategy();
        payContext.setStrategy(ordinaryStrategy);
        System.out.println("普通会员:"+payContext.getPrice(new BigDecimal("100")));

        GoldStrategy goldStrategy = new GoldStrategy();
        payContext.setStrategy(goldStrategy);
        System.out.println("黄金会员:"+payContext.getPrice(new BigDecimal("100")));

        PlatinumStrategy platinumStrategy = new PlatinumStrategy();
        payContext.setStrategy(platinumStrategy);
        System.out.println("白银会员:"+payContext.getPrice(new BigDecimal("100")));
    }
}

结果

普通会员:100

黄金会员:80.0

白银会员:35.0

优化1:新增其他策略,不影响现有的策略

思路:新增策略类,实现策略接口

java 复制代码
package com.geekmice.springbootmybatiscrud.strategy.third;

import java.math.BigDecimal;

public class SilverStrategy implements PayStrategy{
    @Override
    public BigDecimal quote(BigDecimal price) {
        return price.subtract(new BigDecimal("50"));
    }
}

package com.geekmice.springbootmybatiscrud.strategy.third;

import java.math.BigDecimal;

public class Demo {
    public static void main(String[] args) {
        PayContext payContext = new PayContext();
        OrdinaryStrategy ordinaryStrategy = new OrdinaryStrategy();
        payContext.setStrategy(ordinaryStrategy);
        System.out.println("普通会员:"+payContext.getPrice(new BigDecimal("100")));

        GoldStrategy goldStrategy = new GoldStrategy();
        payContext.setStrategy(goldStrategy);
        System.out.println("黄金会员:"+payContext.getPrice(new BigDecimal("100")));

        PlatinumStrategy platinumStrategy = new PlatinumStrategy();
        payContext.setStrategy(platinumStrategy);
        System.out.println("白银会员:"+payContext.getPrice(new BigDecimal("100")));

        SilverStrategy silverStrategy = new SilverStrategy();
        payContext.setStrategy(silverStrategy);
        System.out.println("白金会员:"+payContext.getPrice(new BigDecimal("100")));

    }
}

普通会员:100

黄金会员:80.0

白银会员:35.0

白金会员:50

优化2:策略中出现相同逻辑,如何处理

说明:策略2与策略3处理逻辑中都有需要处理的内容,这个内容可能很长,初始化参数,或者校验参数,远程调用获取数据等操作,都是类似的逻辑,可以抽取到抽象类中,子类需要哪个实现哪个方法,重复的直接在父类操作。

策略工厂

java 复制代码
package com.geekmice.springbootmybatiscrud.strategy.fifth;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
 * @author mbp
 * @date 2025-02-11
 */
public class StrategyFactory {
    /**
     * 设置策略map
     */
    private static Map<String, Strategy> strategyMap = new HashMap<>(16);

    public static Strategy getStrategyService(String type) {
        return strategyMap.get(type);
    }

    /**
     * 提前策略装入 strategyMap
     */
    public static void register(String type, Strategy strategy) {
        if (Objects.isNull(type)) {
            return;
        }
        strategyMap.put(type, strategy);
    }
}

策略接口

java 复制代码
package com.geekmice.springbootmybatiscrud.strategy.fifth;

import org.springframework.beans.factory.InitializingBean;

import java.math.BigDecimal;
/**
 * @author mbp
 * @date 2025-02-11
 */
public interface Strategy extends InitializingBean {
    BigDecimal quote(BigDecimal price);

}

模板方式抽象类

java 复制代码
package com.geekmice.springbootmybatiscrud.strategy.fifth;

/**
 * @author mbp
 * @date 2025-02-11
 */
public abstract class BaseMember {
    /**
     * 需要父类执行关键重复逻辑
     */
    protected void exec(){
        System.out.println("处理内容");
    }

}

具体策略1

java 复制代码
package com.geekmice.springbootmybatiscrud.strategy.fifth;

import org.springframework.stereotype.Component;

import java.math.BigDecimal;
/**
 * @author mbp
 * @date 2025-02-11
 */
@Component
public class OrdinaryStrategy extends BaseMember  implements Strategy {
    @Override
    public BigDecimal quote(BigDecimal price) {
        this.exec();
        return price;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        StrategyFactory.register("1",this);
    }
}

具体策略2

java 复制代码
package com.geekmice.springbootmybatiscrud.strategy.fifth;

import org.springframework.stereotype.Component;

import java.math.BigDecimal;
/**
 * @author mbp
 * @date 2025-02-11
 */
@Component
public class GoldStrategy extends BaseMember implements Strategy {
    @Override
    public BigDecimal quote(BigDecimal price) {
        BigDecimal res = price.multiply(new BigDecimal("0.8"));
        this.exec();
        return res;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        StrategyFactory.register("2", this);
    }

}

具体策略3

java 复制代码
package com.geekmice.springbootmybatiscrud.strategy.fifth;

import org.springframework.stereotype.Component;

import java.math.BigDecimal;
/**
 * @author mbp
 * @date 2025-02-11
 */
@Component
public class PlatinumStrategy extends BaseMember implements Strategy {
    @Override
    public BigDecimal quote(BigDecimal price) {
        BigDecimal res = price.subtract(new BigDecimal("50")).multiply(new BigDecimal("0.7"));
        return res;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        StrategyFactory.register("3", this);
    }
}

测试类

java 复制代码
package com.geekmice.springbootmybatiscrud.controller;

import com.geekmice.springbootmybatiscrud.dao.StudentMapper;
import com.geekmice.springbootmybatiscrud.pojo.Student;
import com.geekmice.springbootmybatiscrud.strategy.fifth.Strategy;
import com.geekmice.springbootmybatiscrud.strategy.fifth.StrategyFactory;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Administrator
 */
@RestController
@RequestMapping("/student")
public class StudentController {
    @Resource
    private StudentMapper studentMapper;

    @GetMapping(value = "queryAll")
    public List<Student> queryAll() {
        Strategy strategyService = StrategyFactory.getStrategyService("1");
        System.out.println(strategyService.quote(new BigDecimal("1000")));
        Strategy strategyService2 = StrategyFactory.getStrategyService("2");
        System.out.println(strategyService2.quote(new BigDecimal("1000")));
        Strategy strategyService1 = StrategyFactory.getStrategyService("3");
        System.out.println(strategyService1.quote(new BigDecimal("1000")));
        return new ArrayList<>();

    }

}

优化3:传递策略类型

根据某个策略类型,执行某个策略逻辑

思路:需要保证某个类型对应某个策略类,通过spring中InitializingBean接口初始化bean,项目启动过程执行实现InitializingBean接口中的afterPropertiesSet方法,在这个方法中初始化map中指定的策略。

策略接口

java 复制代码
public interface Strategy extends InitializingBean {
    BigDecimal quote(BigDecimal price);
}

策略工厂

java 复制代码
package com.geekmice.springbootmybatiscrud.strategy.fourth;

import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class StrategyFactory {
    /**
     * 设置策略map
     */
    private static Map<String, Strategy> strategyMap = new HashMap<>(16);

    public static Strategy getStrategyService(String type) {
        return strategyMap.get(type);
    }

    /**
     * 提前策略装入 strategyMap
     */
    public static void register(String type, Strategy strategy) {
        if (Objects.isNull(type)) {
            return;
        }
        strategyMap.put(type, strategy);
    }
}

具体策略1

java 复制代码
package com.geekmice.springbootmybatiscrud.strategy.fourth;

import com.geekmice.springbootmybatiscrud.strategy.third.PayStrategy;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
@Component
public class OrdinaryStrategy implements Strategy {
    @Override
    public BigDecimal quote(BigDecimal price) {
//        System.out.println("都要处理的内容");
        return price;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("11111111111");
        StrategyFactory.register("1",this);
    }
}

具体策略2

java 复制代码
package com.geekmice.springbootmybatiscrud.strategy.fourth;

import com.geekmice.springbootmybatiscrud.strategy.third.PayStrategy;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
@Component
public class GoldStrategy implements Strategy {
    @Override
    public BigDecimal quote(BigDecimal price) {
        BigDecimal res = price.multiply(new BigDecimal("0.8"));
        return res;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("222222222222");
        StrategyFactory.register("2",this);
    }
}

具体策略3

java 复制代码
package com.geekmice.springbootmybatiscrud.strategy.fourth;

import com.geekmice.springbootmybatiscrud.strategy.third.PayStrategy;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
@Component
public class PlatinumStrategy implements Strategy {
    @Override
    public BigDecimal quote(BigDecimal price) {
        // 都要处理的内容
        // System.out.println("都要处理的内容");
        BigDecimal res = price.subtract(new BigDecimal("50")).multiply(new BigDecimal("0.7"));
        return res;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("3333333333333");
        StrategyFactory.register("3",this);
    }

}

测试

java 复制代码
package com.geekmice.springbootmybatiscrud.controller;

import com.geekmice.springbootmybatiscrud.dao.StudentMapper;
import com.geekmice.springbootmybatiscrud.pojo.Student;
import com.geekmice.springbootmybatiscrud.strategy.first.StrategyFactory;
import com.geekmice.springbootmybatiscrud.strategy.fourth.Strategy;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Administrator
 */
@RestController
@RequestMapping("/student")
public class StudentController {
    @Resource
    private StudentMapper studentMapper;

    @GetMapping(value = "queryAll")
    public List<Student> queryAll() {

        Strategy strategyService =StrategyFactory.getStrategyService("1");
        System.out.println(strategyService);
        System.out.println(strategyService.quote(new BigDecimal("1000")));

        return new ArrayList<>();

    }

}
相关推荐
拆房老料1 天前
【第四部分:Agentic 智能体设计模式】17. Agent 路由模式详解:从意图识别到动态模型选择
java·设计模式·ai编程·策略模式
zhangfeng11334 天前
com.apple.quarantine 并不是乱码,而是 macOS Gatekeeper 给下载文件自动打上的“隔离属性
macos·策略模式
lpfasd1235 天前
Ollama 还是 LM Studio:在 24GB 的 M6 Mac 上,我把 Ollama 卸载了
macos·策略模式
福大大架构师每日一题7 天前
ollama v0.40.11发布:macOS原生语音生成上线,d3决策模型正式加入
macos·策略模式
AIex-YH10 天前
发酵罐里点一盏灯:光发酵,正在重算微藻蛋白的成本账
运维·制造·策略模式
snakecy11 天前
macOS 安装 LaTeX 全流程指南:从 MacTeX 到中文排版
macos·策略模式
钱栈up15 天前
从 macOS 切回 Windows,我用 5 个免费工具把 80% 操作习惯搬了回来
windows·macos·策略模式
kunicoding17 天前
C++ 策略模式实战:写一个可以“一键换输出“的日志系统
开发语言·c++·策略模式
峥嵘life18 天前
Android16 开机后立即打开相机闪退问题分析与解决总结
android·开发语言·数码相机·策略模式
智慧城市203020 天前
关键供应商连续交付不合格批次,说明质量风险可能持续存在。企业需要建立“批次隔离、加严检验、驻厂遏制、复检放行、供应商升级”的处置闭环,同时统筹保供。
数据分析·策略模式·战略咨询·流程管理