策略+工厂模式实现三方渠道业务

107 阅读6分钟

从业多年,也算是用上了设计模式。分享记录一下最近实际项目中采用设计模式的技术方案。大佬轻喷,我就是想记录一下。

背景

项目需要对接多家三方渠道进行入会和退会操作。各个平台渠道的数据分表存储,核心流程基本一致,但三方渠道的参数及相关逻辑存在差异。以下以解绑操作为例,分别采用策略模式、工厂模式和策略+工厂模式实现。

1. 策略模式

定义策略接口

public interface PlatformStrategy {
    void unBind(UserInfo userInfo);
    UserInfo getUserInfo(Long id);
    PlatformChannelEnum getPlatformEnum();
}

具体策略 - A平台

@Service
public class PlatformAStrategyImpl implements PlatformStrategy {
    
    @Resource
    private PlatformAMapper aMapper;
    
    @Override
    public void unBind(UserInfo userInfo) {
        // A平台的解绑逻辑
        System.out.println("解绑A平台用户,用户ID:" + userInfo.getId());
    }

    @Override
    public UserInfo getUserInfo(Long id) {
        // 获取A平台用户信息的逻辑
        System.out.println("获取A平台用户信息的逻辑,用户ID:" + id);
        UserInfo userInfo = new UserInfo();
        return userInfo;
    }

    @Override
    public PlatformChannelEnum getPlatformEnum() {
        // 平台标识 -- A
        return PlatformChannelEnum.A;
    }
}

具体策略 - B平台

@Service
public class PlatformBStrategyImpl implements PlatformStrategy {

    @Resource
    private PlatformBMapper bMapper;

    @Override
    public void unBind(UserInfo userInfo) {
        // B平台的解绑逻辑
        System.out.println("解绑B平台用户,用户ID:" + userInfo.getId());
    }

    @Override
    public UserInfo getUserInfo(Long id) {
        // 获取B平台用户信息的逻辑
        System.out.println("获取B平台用户信息的逻辑,用户ID:" + id);
        UserInfo userInfo = new UserInfo();
        return userInfo;
    }

    @Override
    public PlatformChannelEnum getPlatformEnum() {
        // 平台标识 -- B
        return PlatformChannelEnum.B;
    }
}

Service 层实现

@Service
public class UserPlatformServiceImpl implements UserPlatformService {

    @Autowired
    private PlatformAStrategyImpl aStrategy;
    @Autowired
    private PlatformBStrategyImpl bStrategy;

    @Override
    public void userUnbind(String uid, UnbindReq request) {
        String platform = request.getPlatform();
        Long id = request.getId();

        PlatformStrategy strategy = null;
        // 根据传递的参数来决定使用哪个策略
        if ("A".equals(platform)) {
            strategy = aStrategy;
        } else if ("B".equals(platform)) {
            strategy = bStrategy;
        } else {
            throw new ReturnException(ReturnEnum.UNKNOWN_PLATFORM_ERROR);
        }
        
        UserInfo userInfo = strategy.getUserInfo(id);
        strategy.unBind(userInfo);
    }
}

优点

  • 逻辑简单,易于理解:直接使用策略接口,实现清晰。

缺点

  • 耦合度较高:需要知道所有策略类的名称,客户端与策略类耦合度较高。

2. 工厂模式

定义平台接口

public interface PlatformService {
    void unBind(UserInfo userInfo);
    UserInfo getUserInfo(Long id);
    PlatformChannelEnum getPlatformEnum();
}

A平台实现

@Service
public class PlatformAStrategyImpl implements PlatformService {
    
    @Resource
    private PlatformAMapper aMapper;
    
    @Override
    public void unBind(UserInfo userInfo) {
        // A平台的解绑逻辑
        System.out.println("解绑A平台用户,用户ID:" + userInfo.getId());
    }

    @Override
    public UserInfo getUserInfo(Long id) {
        // 获取A平台用户信息的逻辑
        System.out.println("获取A平台用户信息的逻辑,用户ID:" + id);
        UserInfo userInfo = new UserInfo();
        return userInfo;
    }

    @Override
    public PlatformChannelEnum getPlatformEnum() {
        // 平台标识 -- A
        return PlatformChannelEnum.A;
    }
}

B平台实现

@Service
public class PlatformBStrategyImpl implements PlatformService {

    @Resource
    private PlatformBMapper bMapper;

    @Override
    public void unBind(UserInfo userInfo) {
        // B平台的解绑逻辑
        System.out.println("解绑B平台用户,用户ID:" + userInfo.getId());
    }

    @Override
    public UserInfo getUserInfo(Long id) {
        // 获取B平台用户信息的逻辑
        System.out.println("获取B平台用户信息的逻辑,用户ID:" + id);
        UserInfo userInfo = new UserInfo();
        return userInfo;
    }

    @Override
    public PlatformChannelEnum getPlatformEnum() {
        // 平台标识 -- B
        return PlatformChannelEnum.B;
    }
}

工厂类

@Component
public class PlatformServiceFactory {
    
    private final Map<String, PlatformService> platformServiceMap = new HashMap<>();

    @Autowired
    public PlatformServiceFactory(List<PlatformService> services) {
        services.forEach(service -> {
            String platformType = service.getPlatformEnum().getPlatform();
            platformServiceMap.put(platformType, service);
        });
    }

    public PlatformService getService(String platform) {
        PlatformService service = platformServiceMap.get(platform);
        if (service == null) {
            throw new ReturnException(ReturnEnum.UNKNOWN_PLATFORM_ERROR);
        }
        return service;
    }
}

Service 层实现

@Service
public class UserPlatformServiceImpl implements UserPlatformService {
    
    @Autowired
    private PlatformServiceFactory serviceFactory;

    @Override
    public void userUnbind(String uid, UserUnbindReq request) {
        String platform = request.getPlatform();
        Long id = request.getId();

        // 获取策略对象
        PlatformService service = serviceFactory.getService(platform);

        // 获取用户信息
        UserInfo userInfo = service.getUserInfo(id);

        // 执行解绑操作
        service.unBind(userInfo);
    }
}

优点

  • 降低耦合度:通过工厂获取策略对象,无需知道具体策略类的实现。

缺点

  • 工厂类逻辑复杂:工厂类需要维护策略映射,当策略种类较多时,逻辑可能会变得复杂。

3. 策略 + 工厂模式

定义策略接口

public interface PlatformStrategy {
    void unBind(UserInfo userInfo);
    UserInfo getUserInfo(Long id);
    PlatformChannelEnum getPlatformEnum();
}

A平台具体策略

@Service
public class PlatformAStrategyImpl implements PlatformStrategy {
    
    @Resource
    private PlatformAMapper aMapper;
    
    @Override
    public void unBind(UserInfo userInfo) {
        // A平台的解绑逻辑
        System.out.println("解绑A平台用户,用户ID:" + userInfo.getId());
    }

    @Override
    public UserInfo getUserInfo(Long id) {
        // 获取A平台用户信息的逻辑
        System.out.println("获取A平台用户信息的逻辑,用户ID:" + id);
        UserInfo userInfo = new UserInfo();
        return userInfo;
    }

    @Override
    public PlatformChannelEnum getPlatformEnum() {
        // 平台标识 -- A
        return PlatformChannelEnum.A;
    }
}

B平台具体策略

@Service
public class PlatformBStrategyImpl implements PlatformStrategy {

    @Resource
    private PlatformBMapper bMapper;

    @Override
    public void unBind(UserInfo userInfo) {
        // B平台的解绑逻辑
        System.out.println("解绑B平台用户,用户ID:" + userInfo.getId());
    }

    @Override
    public UserInfo getUserInfo(Long id) {
        // 获取B平台用户信息的逻辑
        System.out.println("获取B平台用户信息的逻辑,用户ID:" + id);
        UserInfo userInfo = new UserInfo();
        return userInfo;
    }

    @Override
    public PlatformChannelEnum getPlatformEnum() {
        // 平台标识 -- B
        return PlatformChannelEnum.B;
    }
}

定义策略工厂

@Component
public class PlatformStrategyFactory {

    private static final Map<String, PlatformStrategy> PLATFORM_STRATEGY_MAP = new HashMap<>();

    @Autowired
    public PlatformStrategyFactory(List<PlatformStrategy> strategies) {
        strategies.forEach(strategy -> {
            String platformType = strategy.getPlatformEnum().getPlatform();
            PLATFORM_STRATEGY_MAP.put(platformType, strategy);
        });
    }

    public PlatformStrategy chooseStrategy(String type) {
        if (!PLATFORM_STRATEGY_MAP.containsKey(type)) {
            throw new ReturnException(ReturnEnum.UNKNOWN_PLATFORM_ERROR);
        }
        return PLATFORM_STRATEGY_MAP.get(type);
    }
}

Service 层实现

@Service
public class UserPlatformServiceImpl implements UserPlatformService {
    
    @Autowired
    private PlatformStrategyFactory strategyFactory;

    @Override
    public void userUnbind(String uid, UserUnbindReq request) {
        String platform = request.getPlatform();
        Long id = request.getId();

        // 获取策略对象
        PlatformStrategy platformStrategy = strategyFactory.chooseStrategy(platform);

        // 获取用户信息
        UserInfo userInfo = platformStrategy.getUserInfo(id);

        // 执行解绑操作
        platformStrategy.unBind(userInfo);
    }
}

优点

  • 客户端与策略类解耦:客户端通过工厂类获取策略对象,无需直接实例化具体策略类,降低耦合度。

  • 策略类独立性:每个策略类独立实现接口,便于单独维护和扩展。

  • 新增策略类方便:新增平台策略时,只需实现接口并注册到工厂类,符合开闭原则。

  • 动态选择策略:客户端可根据平台类型动态选择策略对象,灵活性高。

  • 工厂类集中管理:工厂类集中管理策略对象的创建逻辑,避免重复编写策略选择代码。

  • 职责清晰:工厂类、策略类和 Service 层职责明确,便于维护。

  • 集中管理:工厂类集中管理策略映射关系,便于调试和管理。

缺点

  • 策略种类多时:工厂类中的映射表会变得庞大,逻辑可能复杂。

  • 查找开销:工厂类每次获取策略对象时需在映射表中查找,可能带来性能开销。

  • 初始化开销:工厂类在初始化时需加载所有策略类,可能增加启动时间。


总结

特性策略+工厂结合策略模式工厂模式
解耦程度
扩展性易于扩展易于扩展扩展性一般
灵活性
复杂度中等
推荐场景复杂系统,需灵活扩展简单场景,需灵活切换对象创建复杂,需统一管理

其实在项目上线后总结下来,还是策略+工厂是比较符合实际需求,也曾考虑过每个策略实现不同类型的出入参,实际看下来维护会比较困难,后续如果再额外增加C,D,E等平台只需要实现策略即可。不过项目初期时候很多需求没明确没办法定下模式,导致开始还都是if-else,switch等形式,随着项目进行逐步进行整个模式改造。