1、场景

当业务中有多个运行策略和规则时,通常会采用工厂的设计模式来降低耦合,提升代码未来的可扩展性,现在遇到这样一段逻辑:
有这样一个接口

public interface ILogicFilter{

}

它有如下实现类

@Slf4j  
@Component  
@LogicStrategy(logicMode = DefaultLogicFactory.LogicModel.RULE_BLACKLIST)  
public class RuleBackListLogicFilter implements
ILogicFilter<RuleActionEntity.RaffleBeforeEntity> {

}
```JAVA
@Slf4j  
@Component  
@LogicStrategy(logicMode = DefaultLogicFactory.LogicModel.RULE_WIGHT)  
public class RuleWeightLogicFilter implements ILogicFilter<RuleActionEntity.RaffleBeforeEntity> {
```Java
@Target({ElementType.TYPE})  
@Retention(RetentionPolicy.RUNTIME)  
public @interface LogicStrategy {  

    DefaultLogicFactory.LogicModel logicMode();  
}

现在业务要在不同的情况下使用 RuleBackListLogicFilter 和 RuleWeightLogicFilter 的定义规则,并且未来还会有许多规则可能会被扩展进来

这个时候如何统一管理和根据情况注入对应的规则实体类是一个问题?
因此在此使用了一个工厂设计模式

@Service  
public class DefaultLogicFactory {  

    public Map<String, ILogicFilter<?>> logicFilterMap = new ConcurrentHashMap<>();  

    public DefaultLogicFactory(List<ILogicFilter<?>> logicFilters) {  
        logicFilters.forEach(logic -> {  
            LogicStrategy strategy = AnnotationUtils.findAnnotation(logic.getClass(), LogicStrategy.class);  
            if (null != strategy) {  
                logicFilterMap.put(strategy.logicMode().getCode(), logic);  
            }  
        });  
    }  

    public <T extends RuleActionEntity.RaffleEntity> Map<String, ILogicFilter<T>> openLogicFilter() {  
        return (Map<String, ILogicFilter<T>>) (Map<?, ?>) logicFilterMap;  
    }  

    @Getter  
    @AllArgsConstructor    public enum LogicModel {  

        RULE_WIGHT("","",""),  
        RULE_BLACKLIST("","",""),  
        RULE_WHITELIST("","",""),  
        RULE_LOCK("","",""),  
        RULE_LUCK_AWARD("","",""),  

        ;  

        private final String code;  
        private final String info;  
        private final String type;  

        public static boolean isCenter(String code){  
            return "center".equals(LogicModel.valueOf(code.toUpperCase()).type);  
        }  

        public static boolean isAfter(String code){  
            return "after".equals(LogicModel.valueOf(code.toUpperCase()).type);  
        }  
    }  

}

2、个人思考

学习这个项目最开始遇到这块的时候,其实一直在思考一个问题这个工厂模式,我们在使用时往往是直接使用

@Resource  
private DefaultLogicFactory logicFactory;

它虽然有对外暴露的方法 openLogicFilter,但是其中似乎并没有我们熟悉的工厂架构例如:

public class StoreFactory {  
    public ICommodity getCommodityService(Integer type) {  
        if (null == type) return null;  
        if (1 == type) return new A();  
        if (2 == type) return new B();  
        if (3 == type) return new ();  
        throw new RuntimeException("******");  
    }  
}

这样的一个针对某种类型的构建然后返回。
所以在进行对应的规则选取时,它是如何从中拿到所有的规则的拿到规则的过程中,具体是怎样一个流程

在思考时猜测这会不会根 spring 的 bean 管理有关?

后面在查询资料的过程中才发现这里其实是运用了 IOC 的依赖注入的构造函数注入

这个工厂有一个 @Service 注解,而每一个 ILogicFilter 的实现类都有一个 @Component 注解,当使用这些注解时,spring 会将这些类识别为一个 bean 交由 IOC 容器管理,而实现 IOC 的一种方式就是依赖注入,其中依赖注入又包含了构造函数注入。
于是在我们使用

@Resource  
private DefaultLogicFactory logicFactory;

的时候,spring 便会自动为我们加载一个 DefaultLogicFactory 的实例对象,这个实例对象在使用构造函数初始化时,发现需要依赖 ILogicFilter 的子类,于是 Spring会查找所有实现 ILogicFilter 接口且被容器管理的Bean, 并将这些 bean 组装成列表加载进工厂的构造函数,于是这个工厂便得到了所有的规则类。

3、IOC 与 DI 的补充

IoC (Inversion of Control):控制反转,将程序中对象的调用权由程序本身交由容器管理,通过容器实现对象组件的管理和装配, 实际就是对组件对象控制权的一种转移。它有依赖注入与依赖查找两种实现方式。

DI(Dependency Injection):依赖注入,即组件之间的依赖关系由容器在系统运行时决定,即容器动态的将对应组件注入到关联组件之内。依赖注入是当下最流行的 IOC 实现方式。依赖注入分为:接口注入Setter注入, 构造器注入 三种方式。==依赖注入的基本原则是==:应用组件(需要依赖的对象)不应该有任何查找被依赖资源的逻辑功能代码,并且也不应该具有任何装配的工作,这两部分(查找依赖资源,进行装配)的工作应该有 IOC 容器去负责实现,IOC 容器把符合依赖关系的对象通过属性或者构造器传递给应用组件。

接口注入示例:

interface OneBean{  
    void createOneBean(OneBean oneBean);  

    void test();  
}  

interface TwoBean{  
    void test();  
}  

class MyBean implements OneBean,TwoBean{  
    OneBean oneBean; // 需要被注入的接口依赖  

    @Override  
    public void createOneBean(OneBean oneBean) { // 接口注入方法  
        this.oneBean=oneBean; //实际注入  
    }  

    @Override  
    public void test() {  

    }
}

Setter 注入

class MyBean2 implements TwoBean{  
    OneBean oneBean; // 需要被注入的接口依赖  
    /**  
     * setter方法注入  
     * @param oneBean  
     */  
    public void setUserMapper(OneBean oneBean) {  
        this.oneBean = oneBean;  
    }  
    @Override  
    public void test() {  

    }}

构造函数注入:如 1、场景
其余依赖查找请参考 4、参考文献 的文章

4、参考文献

[1].# 控制反转(IoC)与依赖注入(DI)详解

[2]. 场景参考