设计模式——工作中对面向接口编程、工厂模式的使用
概念
接口
- 可以理解成是一种标准(规范),在广义泛指一组标准的集合,它规定了实现该接口的类或者接口必须也拥有这一组规则。
面向接口编程
- 面向接口编程(Interface Oriented Programming:OIP)是一种编程思想,接口作为实体抽象出来的一种表现形式,用于抽离内部实现进行外部沟通,最终实现内部变动而不影响外部与其他实现交互。
抽象工厂模式
- 抽象工厂模式,即Abstract Factory Pattern,提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类;具体的工厂负责实现具体的产品实例。
简单工厂模式
- 定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
抽象工厂模式与工厂方法模式最大的区别:抽象工厂中每个工厂可以创建多种类的产品;而工厂方法每个工厂只能创建一类
使用
在项目实际开发中,许多的应用程序有着共同的操作,比如查看详情、链接跳转、文件打印等等,只是每个应用有各自的逻辑实现,本次以文件打印和子表数据获取为例,使用面向接口编程和工厂模式的思想进行开发,让每个应用都使用同一个接口,方便后续的维护和拓展。
接口
- 文件打印接口
public interface ExportTemplateFile {
void exportFile();
}
- 子表数据获取接口
public interface SubTableDomian {
R<PopupVo<Object>> getDomain();
}
抽象工厂
- 定义抽象方法,并返回接口类。
- className:类名称,用于通过反射获取具体的实现类
- requestDto:请求的参数
public abstract class GboEventAbstractFactory {
public abstract ExportTemplateFile getExportClass(String className, RequestDto requestDto);
public abstract SubTableDomian getSubTableDomainClass(String className, RequestDto requestDto);
}
具体工厂
- 具体工厂继承抽象工厂,并重写抽象方法,通过反射的获取具体的实现类型
public class ExportTempFlieFactory extends GboEventAbstractFactory{
@Override
public ExportTemplateFile getExportClass(String className, RequestDto requestDto) {
if(StringUtils.isBlank(className)){
return null;
}
try {
Class<?> clazz = Class.forName(className);
ExportTemplateFile exportTemplateFile = (ExportTemplateFile) clazz.getDeclaredConstructor().newInstance();
// 查找父类中包含requestDto属性的类
Class<?> superClass = clazz.getSuperclass();
while (superClass != null) {
try {
Field field = superClass.getDeclaredField("requestDto");
field.setAccessible(true);
field.set(exportTemplateFile, requestDto);
break;
} catch (NoSuchFieldException e) {
superClass = superClass.getSuperclass();
}
}
return exportTemplateFile;
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
e.printStackTrace();
return null;
}
}
@Override
public SubTableDomian getSubTableDomainClass(String className, RequestDto requestDto) {
return null;
}
}
public class SubTableDomainFactory extends GboEventAbstractFactory{
@Override
public ExportTemplateFile getExportClass(String className, RequestDto requestDto) {
return null;
}
@Override
public SubTableDomian getSubTableDomainClass(String className, RequestDto requestDto) {
return null;
}
}
类型枚举
public enum TypeEnum {
EXPORT("EXPORT","导出文件"),
DOMAIN("DOMAIN","子表数据");
private String type;
private String name;
TypeEnum(String type, String name) {
this.type = type;
this.name = name;
}
public String getType() {
return type;
}
public String getName() {
return name;
}
}
具体工厂生产类
public class FactoryProducer {
public static GboEventAbstractFactory getFactory(String type) {
if (type == null) {
return null;
}
if (TypeEnum.EXPORT.getType().equals(type)) {
return new ExportTempFlieFactory();
} else if (TypeEnum.DOMAIN.getType().equals(type)) {
return new SubTableDomainFactory();
} else {
return null;
}
}
}
统一处理
public class CommonEvent{
public void exportFile() {
// 获取请求参数(包含枚举类型和全类名,类名建议通过数据配置)
String eventtype = MapUtil.getStr(argsMap, "EVENTTYPE", null);
GboEventAbstractFactory factory = FactoryProducer.getFactory(eventtype);
ExportTemplateFile exportClass = factory.getExportClass(handleclass,requestDto);
exportClass.exportFile();
}
}
使用
public class Test implements ExportTemplateFile,SubTableDomian{
@Override
public void exportFile() {
log.info(this.getAppName() + this.getClass().getSimpleName() + "导出文件....");
}
@Override
public R<PopupVo<Object>> getDomain() {
log.info(this.getClass().getSimpleName() + "获取子表数据....");
return null;
}
}
这样,系统暴露给外部的只需要一个接口,每个应用只需要配置一个处理类,并在处理类中实现接口逻辑,后续拓展的话只需要添加接口及实现接口的逻辑即可,前端调用的API无需修改。这样也可以保证每个类处理自己的事件,方便维护。