java设计模式-工厂模式

今天起,在我的博客开一个专题,专门写一些个人对于设计模式的理解,众所周知,常用的设计模式有大概23种,那让我们一个个来看看日常工作中如何更好的使用他们吧~

首先要讲的是工厂模式,直接用例子跟大家讲清楚这些事情,我们先定义一个奖励发送的接口类:

public interface RewardService {

    /**
     * 发放奖励
     * @param userId 用户id
     * @param rewordId 奖励品id
     * @param bizId 业务唯一code
     * @param extMap 扩展字段
     */
    void giveReword(Long userId, Long rewordId, String bizId, Map<String,String> extMap);
}

紧接着有三个不同的实现类(Strategy为自定义注解,后续会使用到):

@Slf4j
@Service
@Strategy(rewardType = Constants.REWARD.ECARD_REWORD)
public class ECardRewardSpringService implements RewardSpringService {
    @Override
    public void giveReword(Long userId, Long rewordId, String bizId, Map<String, String> extMap) {
        //模仿发送奖励代码
        log.info("发送卡片奖励给用户:{},奖励为:{},业务code为:{}",userId,rewordId,bizId);
    }
}
@Slf4j
@Slf4j
@Service
@Strategy(rewardType = Constants.REWARD.MATERIAL_REWOD)
public class MaterialRewardSpringService implements RewardSpringService {
    @Override
    public void giveReword(Long userId, Long rewordId, String bizId, Map<String, String> extMap) {
        //模仿发送奖励代码
        log.info("发送实物奖励给用户:{},奖励为:{},业务code为:{}",userId,rewordId,bizId);
    }
}
@Slf4j
@Service
@Strategy(rewardType = Constants.REWARD.VIRTUAL_REWORD)
public class VirtualRewardSpringService implements RewardSpringService {
    @Override
    public void giveReword(Long userId, Long rewordId, String bizId, Map<String, String> extMap) {
        //模仿发送奖励代码
        log.info("发送虚拟奖励给用户:{},奖励为:{},业务code为:{}",userId,rewordId,bizId);
    }
}

那我们想要调用不同的奖励发放逻辑,通常的代码都是这样写的

public class SimpleFactoryTests {

    @Test
    public void testGetRewordByUsual(Integer rewardType){
        if(rewardType == 1){
            RewardService rewardService = new ECardRewardService();
            rewardService.giveReword(111L,222L,"reword1",new HashMap<>());
        } else if(rewardType == 2){
            RewardService rewardService = new MaterialRewardService();
            rewardService.giveReword(222L,333L,"reword2",new HashMap<>());
        } else if(rewardType == 3){
            RewardService rewardService = new VirtualRewardService();
            rewardService.giveReword(444L,555L,"reword3",new HashMap<>());
        }
    }


}

当后面新增新的的奖励类型的时候,我们就会来改这段代码,新增if else判断,久而久之,这段代码就会越来越长,最终成为s***山代码了,那采用工厂模式的话,就可以轻松将去除掉这边的if else语句了,那我们从浅入深,看看工厂模式如何正确运用的吧~

简单工厂模式

话不多说,直接上代码:

public class SimpleFactory {

    /**
     * 通过奖励类型返回奖励服务类
     * @param rewordType 奖励类型
     * @return
     */
    public RewardService getRewordServiceByType(Integer rewordType){
        if(rewordType == null){
            return null;
        }
        if(rewordType == 1){
            return new ECardRewardService();
        }
        if(rewordType == 2){
            return new MaterialRewardService();
        }
        if(rewordType == 3){
            return new VirtualRewardService();
        }
        throw new RuntimeException("不存在的奖励类型");
    }


    public RewardService getRewordServiceByClazz(Class<? extends RewardService> clazz){
        if (clazz == null){
            return null;
        }
        try {
            return clazz.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

}

可以看到,在这个方法中,提供了两个方法,一个通过类型返回service对象,一个通过Class类型返回对象,下面是对应的测试代码:

public class SimpleFactoryTests {
    
    @Test
    public void testGetRewordServiceByType(){
        SimpleFactory simpleFactory = new SimpleFactory();
        RewardService rewardService = simpleFactory.getRewordServiceByType(2);
        rewardService.giveReword(222L,333L,"reword2",new HashMap<>());
    }


    @Test
    public void testGetRewordServiceByClazz(){
        SimpleFactory simpleFactory = new SimpleFactory();
        RewardService rewardService = simpleFactory.getRewordServiceByClazz(VirtualRewardService.class);
        rewardService.giveReword(444L,555L,"reword3",new HashMap<>());
    }


}

就这其实就实现了一个最简单的工厂方法了,但是离我们用到实际工作中其实还差的很远,因为实际工作的,我们会更多的与Spring去结合使用,那看看我平常都是怎么写的吧~

结合Spring的工厂模式_1

首先定义工厂配置类,用于职责隔离

public class RewardConfig {

    protected static Map<Constants.REWARD, RewardSpringService> factoryMap = new ConcurrentHashMap<>();

    @Resource
    private ECardRewardSpringService eCardRewardSpringService;

    @Resource
    private MaterialRewardSpringService materialRewardSpringService;

    @Resource
    private VirtualRewardSpringService virtualRewardSpringService;

    @PostConstruct
    public void init(){
        factoryMap.put(Constants.REWARD.VIRTUAL_REWORD,virtualRewardSpringService);
        factoryMap.put(Constants.REWARD.MATERIAL_REWOD,materialRewardSpringService);
        factoryMap.put(Constants.REWARD.ECARD_REWORD,eCardRewardSpringService);
    }
}

其次,定义工厂类继承于配置类,给出获取service的方法

@Service
public class RewardFactory extends RewardConfig{

    public RewardSpringService getRewardService(Constants.REWARD rewardType){
        return factoryMap.get(rewardType);
    }

}

结合Spring的工厂模式_2

@Configuration
public class RewardContext {

    /**
     * 利用Spring依赖注入的第一种方式
     * @param eCardRewardSpringService
     * @param materialRewardSpringService
     * @param virtualRewardSpringService
     * @return
     */
    @Bean
    public Map<Constants.REWARD, RewardSpringService> getRewardMap(ECardRewardSpringService eCardRewardSpringService,
                                                                   MaterialRewardSpringService materialRewardSpringService,
                                                                   VirtualRewardSpringService virtualRewardSpringService){
        Map<Constants.REWARD,RewardSpringService> rewardFactoryMap = new HashMap<>(8);
        rewardFactoryMap.put(Constants.REWARD.ECARD_REWORD,eCardRewardSpringService);
        rewardFactoryMap.put(Constants.REWARD.MATERIAL_REWOD,materialRewardSpringService);
        rewardFactoryMap.put(Constants.REWARD.VIRTUAL_REWORD,virtualRewardSpringService);
        return rewardFactoryMap;
    }

}

结合Spring的工厂模式_3

首先也是定义配置类

public class RewardConfig {

    @Resource
    private List<RewardSpringService> rewardList;

    public Map<Constants.REWARD, RewardSpringService> getRewardAutoWireMap() {
        return rewardAutoWireMap;
    }

    protected static Map<Constants.REWARD,RewardSpringService> rewardAutoWireMap = new ConcurrentHashMap<>();

    @PostConstruct
    private void init(){
        rewardList.forEach(reward ->{
            Strategy strategy = AnnotationUtils.findAnnotation(reward.getClass(),Strategy.class);
            if(strategy != null){
                rewardAutoWireMap.put(strategy.rewardType(),reward);
            }
        });
    }
}

其次定义工厂类继承于配置类:

@Service
public class RewardAutowire extends RewardConfig{


    public void getReward(){
        RewardSpringService rewardSpringService = rewardAutoWireMap.get(Constants.REWARD.VIRTUAL_REWORD);
        rewardSpringService.giveReword(555L,666L,"reward_003",new HashMap<>());
    }

}

公用测试方法

@SpringBootTest
public class SpringFactoryTests {

    @Resource
    private RewardFactory rewardFactory;

    @Resource
    private Map<Constants.REWARD, RewardSpringService> rewardMap;

    @Resource
    private RewardAutowire rewardAutowire;


    @Test
    public void getReward1(){
        RewardSpringService rewardSpringService = rewardFactory.getRewardService(Constants.REWARD.ECARD_REWORD);
        rewardSpringService.giveReword(111L,222L,"reward_001",new HashMap<>());
    }

    @Test
    public void getReward2(){
        RewardSpringService rewardSpringService = rewardMap.get(Constants.REWARD.MATERIAL_REWOD);
        rewardSpringService.giveReword(333L,444L,"reward_002",new HashMap<>());
    }

    @Test
    public void getReward3(){
        RewardSpringService rewardSpringService = rewardAutowire.getRewardAutoWireMap().get(Constants.REWARD.VIRTUAL_REWORD);
        rewardSpringService.giveReword(555L,666L,"reward_003",new HashMap<>());
    }
}

总结

在本博客中,讲述了几种工作中常用的实现工厂模式的方式(结合Spring),分别是:

  • 基于单个Bean的依赖注入维护工厂容器
  • 基于@Bean+@Configuration,在初始化时构造工厂容器
  • 基于自定义注解方式自动维护工厂容器

相信总有一款适合大家

你可能感兴趣的:(java,设计模式,spring)