问题:通过策略模式+工厂模式+模板方法模式实现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:传递策略类型

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

思路:需要保证某个类型对应某个策略类,通过springInitializingBean接口初始化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 天前
策略模式与元数据映射模式融合 JSR 380 验证规范实现枚举范围校验
windows·spring·策略模式
木子庆五3 天前
Android设计模式之模板方法模式
android·设计模式·模板方法模式
码界孔乙己4 天前
python策略模式
python·策略模式
Hanson Huang4 天前
23种设计模式-模板方法(Template Method)设计模式
java·设计模式·模板方法模式·行为型设计模式
此木|西贝4 天前
【设计模式】策略模式
设计模式·策略模式
患得患失9496 天前
【设计模式】策略模式(Strategy Pattern)详解
设计模式·bash·策略模式
一恍过去7 天前
SpringBoot通过Map实现天然的策略模式
spring boot·后端·策略模式
Vic101017 天前
Java 中装饰者模式与策略模式在埋点系统中的应用
java·开发语言·策略模式
獨枭7 天前
在 macOS 上配置 VS Code 使用 PowerShell(适配 Homebrew 安装)
macos·策略模式
cijiancao8 天前
23种设计模式中的策略模式
设计模式·策略模式