❓库房地址:github.com/Chengyunlai…

作者:Chengyunlai 语雀 (yuque.com)

邮箱:yunlai_cheng@163.com

1. 介绍

运用布景:依据某些条件匹配相应子完成类的逻辑,见图 1-1

防止:运用IF-ELSE来处理这样的逻辑。原因:不便于后续晋级迭代的维护,能够细心考虑一下,如果考虑不出来还有有疑问,能够提出问题:为什么不便于后续晋级迭代。

工厂模式 - 枚举类

图 1-1

2. 实战

布景: 大模型的布景下,我司有两个事务

  1. ChatGPT3_5;
  2. ChatGPT4_0

现在需求依据用户付费的状况,判别用户到底挑选哪个模型

架构设计图:

全体架构设计如 图 1-2 所示,从Application运用 ChatContext 这个类,传入 User,让其(ChatContext)调用getReplyInfo,依据 User的条件来执行ChatService的完成类。

工厂模式 - 枚举类

我知道,许多朋友肯定想在ChatContextgetReplyInfo这个办法中运用IF-ELSE的办法来控制到底是具体调用3_5还是4_0,咱们防止运用这样的办法,之前说了:这样不便于拓宽代码。

解决的办法是运用枚举类,先上代码,然后去考虑为什么运用枚举类就能够解决逻辑分支的判别了。

2.1. 为什么用枚举类

package top.chengyunlai.architecture.chat;
import java.util.Objects;
/**
 * @author Chengyunlai
 * @description: TODO
 * @date 2023/7/25
 */
public enum ChatEnum {
    CHAT_3_5(1,"chat3"),
    CHAT_4_0(2,"chat4");
    private Integer flag;
    private String serverName;
    ChatEnum(Integer flag, String serverName) {
        this.flag = flag;
        this.serverName = serverName;
    }
    public Integer getFlag() {
        return flag;
    }
    public void setFlag(Integer flag) {
        this.flag = flag;
    }
    public String getServerName() {
        return serverName;
    }
    public void setServerName(String serverName) {
        this.serverName = serverName;
    }
    public static String getStrategyServiceByType(Integer type) {
        for (ChatEnum d : ChatEnum.values()) {
            if (Objects.equals(type, d.getFlag())) {
                return d.getServerName();
            }
        }
        // 兜底处理
        return "chat3";
    }
}

解读: 11 行和 12 行定义了两个枚举类型flag 是条件:匹配用户传入的条件;serverName是对应的服务名(Spring 容器称号),这样的定义就方便后边只需求经过值就能拿到对应的服务称号了。

然后咱们封装了一个办法getStrategyServiceByType,在 38 行。ChatEnum.values()拿出咱们定义的所有的枚举(flag,serverName),然后经过增强 for 循环去判别传入进来的类型去匹配对应的值。

当然兜底处理是返回"chat3"

长处: 这样做的好处就是,新增ChatService子类的时分,只需求新增一个枚举即可。

2.2. ChatContext 的妙用

咱们知道在 ChatContext 需求去调用不同的 ChatService 完成类,有没有什么好的办法将他们注入进来呢?

工厂模式 - 枚举类

  1. 经过枚举类,获取取得对应容器的姓名:String
  2. 那么经过这个姓名就应该能拿到这些容器对应的实例,Yes,Spring 帮咱们能做到这一点,要害点就在这个 Map 方式的注入
@Autowired
private Map<String,ChatService> chatServiceMap;

经过 IDEA 东西咱们能够发现,它指向了两个实例(实例运用@Service注解润饰),这说明运用主动注入的办法 + Map 的办法实际上已经做到了(key:容器名,value:容器实例)。

接下去要考虑的就是,怎么调配枚举类去取对应的 key 即可。

工厂模式 - 枚举类

也就是getReplyInfo办法

public String getReplyInfo(User user){
    // 经过 Map 拿到姓名对应的容器实例
    return chatServiceMap.get(
            // 经过枚举取得对应的容器姓名
            ChatEnum.getStrategyServiceByType(
                    // 条件
                    user.getIsChatGPTType()
            )
    ).getReplyInfo();
}

3. 代码

懂了这个重要的枚举类,咱们就来开发剩余的代码。

3.1. ChatService

工厂模式 - 枚举类

package top.chengyunlai.architecture.chat;
public interface ChatService {
    String getReplyInfo();
}

3.2. ChatServiceImpl3_5

package top.chengyunlai.architecture.chat.impl;
import org.springframework.stereotype.Service;
import top.chengyunlai.architecture.chat.ChatService;
/**
 * @author Chengyunlai
 * @description: TODO
 * @date 2023/7/25
 */
@Service("chat3")
public class ChatServiceImpl3_5 implements ChatService {
    @Override
    public String getReplyInfo() {
        return "chat3.5";
    }
}

3.3. ChatServiceImpl4_0

package top.chengyunlai.architecture.chat.impl;
import org.springframework.stereotype.Service;
import top.chengyunlai.architecture.chat.ChatService;
/**
 * @author Chengyunlai
 * @description: TODO
 * @date 2023/7/25
 */
@Service("chat4")
public class ChatServiceImpl4_0 implements ChatService {
    @Override
    public String getReplyInfo() {
        return "chat4.0";
    }
}

3.4. User 类

工厂模式 - 枚举类

package top.chengyunlai.architecture.chat;
import lombok.Data;
/**
 * @author Chengyunlai
 * @description: TODO
 * @date 2023/7/25
 */
public class User {
    // 是否开启 ChatGPT4,1 为不开启;2 为开启
    private Integer chatGPTType;
    public void setChatGPTType(Integer chatGPTType) {
        this.chatGPTType = chatGPTType;
    }
    public Integer getIsChatGPTType(){
        return this.chatGPTType;
    }
}

3.5. 枚举类

见上

3.6. ChatContext

工厂模式 - 枚举类

package top.chengyunlai.architecture.chat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Map;
/**
 * @author Chengyunlai
 * @description: 对话上下文,归于对话中间件,依据条件挑选对应的真实对话服务
 * @date 2023/7/25
 */
@Service
public class ChatContext {
    @Autowired
    private Map<String,ChatService> chatServiceMap;
    public String getReplyInfo(User user){
        // 经过 Map 拿到姓名对应的容器实例
        return chatServiceMap.get(
                // 经过枚举取得对应的容器姓名
                ChatEnum.getStrategyServiceByType(
                        // 条件
                        user.getIsChatGPTType()
                )
        ).getReplyInfo();
    }
}

如果本文对你有协助的话,记住点个赞再走呀。愿你在技能学习的路上不断的突飞猛进!