Skip to main content

通用工厂的代码思路

· 4 min read

公司的产品,要被多个公司使用,架构师让我设计个方案,有些公司部分需求可能是定制化的,那么不同公司最好走的是不同的实现

相信不少人的想法肯定是多套适配器

如下:

适配器通过jar包的方式被触发器引入,每个公司部署不同的适配器,这样也可以

但有一些情况是,定制化的业务比较少,但是偶尔会存在,那么引入适配器的方案可能成本就过于去高了,就需要从代码上下手,想一种低耦合的办法

说到这里,要感谢Spring提供了IOC容器的这种实现,我们因为有了IOC容器,因此我们就可以很轻松的实现一个通用工厂来减少if else

我的方案是在不同实现上 增加自定义注解

@Documented
@Target({ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Company {

public CorporateIdentity.CompanyCodeEnums name();
}


public class CorporateIdentity {

/**
* 当前租户ID
*/
private static String tenantId;


static {
//TODO 默认应该从配置文件获取,或者从请求头中拿到 后续处理
tenantId = CompanyCodeEnums.BD.getTenantId();
}


public static String getCurrentTenantId() {
return tenantId;
}


public enum CompanyCodeEnums {
XDZ(1,"001","baidu");

private int order;

private String tenantId;

private String desc;

CompanyCodeEnums(int order, String tenantId, String desc) {
this.order = order;
this.tenantId = tenantId;
this.desc = desc;
}

public int getOrder() {
return order;
}

public String getTenantId() {
return tenantId;
}

public String getDesc() {
return desc;
}
}
}

在类上加入这个注解


@Company(name = CorporateIdentity.CompanyCodeEnums.BD)

当然我们公司的具体情况还是有些不同的,我们是有自己的IOC容器的自研框架

因此在从容器获取的写法上,会和spring的写法有些出入,大家可以改一下,实现一下ApplicationContext,然后去写,我这个人比较懒,就不给大家再写一遍了,哈哈

@Xjava
public class CompanyFactory {

/**
* 缓存工厂,缓存当前公司下的所有实例对象
*/
private ConcurrentHashMap<String, Object> cacheObjectFactory = new ConcurrentHashMap<>();

/**
* 获取对象
* @param clazz 需要获取的类的父级
* @return 当前公司下的对象实现
*/
public <T> T getObject(Class<T> clazz) {

Object object = cacheObjectFactory.get(clazz.getName());
if (object != null) {
return (T) object;
}
Map<String, T> objects = XJava.getObjects(clazz);

objects.forEach((className, obj) -> {
if (obj.getClass().isAnnotationPresent(Company.class)) {
Company annotation = obj.getClass().getAnnotation(Company.class);

if (CorporateIdentity.getCurrentTenantId()
.equals(annotation.name().getTenantId())) {
cacheObjectFactory.put(clazz.getName(), obj);
}
}
});
return (T) cacheObjectFactory.get(clazz.getName());
}
}

最后通过getObject()方法,获取目标类的接口,然后他会自动选择具体使用哪个实现类

PusherAdapter pusherAdapter = companyFactory.getObject(pusherAdapter.class);