概述
在开发中工厂模式使用的非常频繁,无非就是无外乎是对象的创建,但是在实践中我们如何使用的比较多…
首先我们要分清楚工厂类和工厂要创建的类,工厂要创建的类,我们平时该怎么定义还是怎么定义,不管是什么工厂模式,都不会影响这一步相关内容,
我们平时往往喜欢使用一个简单的类,单在开发中类的结构是非常复杂的,因此我们不关心类的结构我们只关心工厂相关的实现:
说白了,我们今天就是探讨的红框中的实现,是如何来实现,平时我们听到的名称:
简单工厂,工厂方法, 抽象工厂等等,不管那种模式,一定存在右边的工厂类,往往存在一个顶端接口XXXFactory,并且里面只有一个方法,就是创建对象的方法
- 简单工厂就是分别实现XXXFactory ,开多个工厂类,在使用的过程中进行创建不同的工厂类,这个写法确实简单,
- 上面的方法好理解,但是在开发中使用的比较少, 代码重复太多,我们今天说说几个常用的方式
使用反射
这种方式一般在开发框架中使用比较多,业务代码开发中使用较少, 也就是说我们一个类的体系非常庞大,里面的属性又非常多,继承关系好几层,每一层针对不同的属性进行赋值,要么靠传入的数据,如果没有传入就进行默认赋值
工厂接口
public interface MyCarFactory<T extends Car> {
/**
* Creates a new channel.
*/
T newCar();
}
工厂实现类
package com.factory.reflect;
import io.netty.channel.ChannelException;
import io.netty.channel.ReflectiveChannelFactory;
import io.netty.util.internal.StringUtil;
import java.lang.reflect.Constructor;
import java.util.Objects;
/**
* @author wufagang
* @description
* @date 2022年07月16日 15:58
*/
public class ReflectiveCarFactory<T extends Car> implements MyCarFactory<T> {
private final Constructor<? extends T> constructor;
public ReflectiveCarFactory(Class<? extends T> clazz) {
assert Objects.nonNull(clazz);
try {
this.constructor = clazz.getConstructor();
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
" does not have a public non-arg constructor", e);
}
}
@Override
public T newCar() {
try {
return constructor.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
}
}
@Override
public String toString() {
return StringUtil.simpleClassName(ReflectiveChannelFactory.class) +
'(' + StringUtil.simpleClassName(constructor.getDeclaringClass()) + ".class)";
}
}
至于car相关的类结构可以随便进行定义了,可以是很多层
这里就不在赘述了,自己随便定义就可以
创建对象:
public static void main(String[] args) {
ReflectiveCarFactory<BCcar> bCcarReflectiveCarFactory = new ReflectiveCarFactory<>(BCcar.class);
BCcar bCcar = bCcarReflectiveCarFactory.newCar();
bCcar.run();
ReflectiveCarFactory<AudiCar> audiCarReflectiveCarFactory = new ReflectiveCarFactory<>(AudiCar.class);
AudiCar audiCar = audiCarReflectiveCarFactory.newCar();
audiCar.run();
}
自定义注解的方式
这种方式我经常在业务代码中使用
比如消费一个mq里面数据类型有很多中,如果一般人写代码就是一个方法入口,一串代码进行下去,稍微好点的 多写一下方法,说白了就是一个面向过程的开发,后期代码维护的时候太费劲了,代码可读性性太差直接上干货:
使用的入口
简单吧一行代码, 我们写代码尽可能达到这样的比较
MatrixInfoAnalyerFactory.allHandlerdoHandler(context);
这个类是关键所在,实现思路就是,根据自定义注解,获取所有的处理器,放入map中,
当调用上面那一行代码,就遍历map,让所有的方法执行
package com.jd.viewworld.service.cjg.matrixinfo;
import com.google.common.base.Preconditions;
import com.jd.exception.common.ComponentBusinessException;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* @author wufagang
* @date 2022年05月30日 14:39
*/
@Component
public class MatrixInfoAnalyerFactory implements ApplicationContextAware, InitializingBean {
private static ApplicationContext context;
private static final Map<String, MatrixInfoHandler> handlers = new HashMap<>();
@Override
public void afterPropertiesSet() throws Exception {
String[] names = context.getBeanNamesForAnnotation(MatrixInfoAnalyer.class);
if(ArrayUtils.isEmpty(names)){
throw new ComponentBusinessException("消息处理器为空");
}
for (String name: names) {
Object obj = context.getBean(name);
if(!(obj instanceof MatrixInfoHandler)){
continue;
}
MatrixInfoHandler bean = (MatrixInfoHandler) obj;
MatrixInfoAnalyer annotation = AnnotationUtils.findAnnotation(bean.getClass(), MatrixInfoAnalyer.class);
Preconditions.checkArgument(Objects.nonNull(annotation),"处理器未添加annotation!");
String value = annotation.value();
Preconditions.checkArgument(StringUtils.isNotBlank(value),"处理器未添加value");
//这里不判断重复,如果编写多个相同的,使用最后加载的
handlers.put(value,bean);
}
}
public static void allHandlerdoHandler(MatrixInfoContext context){
if(handlers.isEmpty()){
return;
}
Collection<MatrixInfoHandler> handlerImpl = handlers.values();
handlerImpl.forEach(item->{
item.doHandler(context);
});
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
}
自定义注解:
如果这些handler有顺序要求,我们可以在注解中增加顺序熟悉
package com.jd.viewworld.service.cjg.matrixinfo;
import org.springframework.stereotype.Component;
import java.lang.annotation.*;
@Documented
@Component
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MatrixInfoAnalyer {
String value() default "";
}
handler的定义和实现,这里面写自己的业务代码
public interface MatrixInfoHandler {
void doHandler(MatrixInfoContext context);
}
@MatrixInfoAnalyer("appExtHandler")
public class AppExtHandler extends AbstractmatrixInfoHandler {