一个公网ip可以做几个网站,内蒙古呼和浩特市做网站的公司,邯郸双曜网络科技有限公司,百度权重2的网站写在前面 偶然间看到一篇文章 《Java 中保持扩展性的几种套路和实现》#xff0c;写的不错#xff0c;但是类图画的差了点儿意思。于是#xff0c;自己动手画了画#xff0c;对其中的内容作了一些调整#xff0c;对包做了进一步划分#xff0c;便于理解消化。以下是对Git…写在前面 偶然间看到一篇文章 《Java 中保持扩展性的几种套路和实现》写的不错但是类图画的差了点儿意思。于是自己动手画了画对其中的内容作了一些调整对包做了进一步划分便于理解消化。以下是对GitHub项目 design-pattern-extend 的快览后期将新的套路慢慢补充。 目录 写在前面一、项目结构二、关键信息管道模式过滤器链模式事件分发模式模板工厂模式SPI模式注解模式其他 三、参考资料写在后面系列文章 一、项目结构 以下为GitHub项目 design-pattern-extend 的整体目录结构。images 目录下为设计模式的 plantuml 类图client目录为模式main方法入口。
如果想向学习又懒得敲代码的话具体代码及示例请前往design-pattern-extend 自行获取。
design-pattern-extend
├─images
└─src└─main├─java│ └─cn│ └─thinkinjava│ └─design│ └─pattern│ └─extend│ ├─annotation│ │ └─client│ ├─eventdispatch│ │ ├─client│ │ ├─event│ │ ├─listener│ │ └─source│ ├─filterchain│ │ ├─client│ │ ├─filter│ │ └─request│ ├─pipeline│ │ ├─client│ │ ├─context│ │ └─value│ ├─spi│ │ ├─client│ │ └─service│ │ └─impl│ └─templatefactory│ ├─client│ └─handler│ └─base└─resources└─META-INF└─services二、关键信息
下面简单说一下相关的设计模式扩展思路。
管道模式
管道模式简单说就是想对某个对象进行一些列的操作。
根据面向接口以及抽象的原则 1、“操作”是要抽取出来一个接口我们用管道值表示即value包下的PipelineValue。 2、“某个对象”就是要操作的类我们用上下文表示即context包下的PipelineContext。 3、既然是管道那“操作”得放到管道里面添加/删除操作方法还得执行管道操作方法遍历管道值调用方法即pipeline包下的Pipeline。
这样就形成3个体系看类图
以下为上下文对象
package cn.thinkinjava.design.pattern.extend.pipeline.context;/*** 上下文** author qiuxianbao* date 2024/01/02*/
public interface PipelineContext {String FOR_TEST forTest;void set(String contextKey, Object contextValue);Object get(String contextKey);
}//
package cn.thinkinjava.design.pattern.extend.pipeline.context;import java.util.HashMap;
import java.util.Map;/*** 上下文的具体实现** author qiuxianbao* date 2024/01/02*/
public class StandardPipelineContext implements PipelineContext {private MapString, Object contextMap new HashMap();Overridepublic void set(String contextKey, Object contextValue) {contextMap.put(contextKey, contextValue);}Overridepublic Object get(String contextKey) {return contextMap.get(contextKey);}}
以下为管道值对象 package cn.thinkinjava.design.pattern.extend.pipeline.value;import cn.thinkinjava.design.pattern.extend.pipeline.context.PipelineContext;/*** 管道中的操作对象** author qiuxianbao* date 2024/01/02*/
public interface PipelineValue {/*** 具体的操作** param context 上下文* return*/boolean execute(PipelineContext context);
}//
package cn.thinkinjava.design.pattern.extend.pipeline.value;import cn.thinkinjava.design.pattern.extend.pipeline.context.PipelineContext;
import lombok.extern.slf4j.Slf4j;/*** 管道中的操作对象的抽象** author qiuxianbao* date 2024/01/02*/
Slf4j
public abstract class AbstractPipelineValue implements PipelineValue {Overridepublic boolean execute(PipelineContext context) {log.info({} start, this.getClass().getSimpleName());boolean result doExecute(context);log.info({} end, this.getClass().getSimpleName());return result;}/*** 由子类实现** param context* return*/protected abstract boolean doExecute(PipelineContext context);
}//
package cn.thinkinjava.design.pattern.extend.pipeline.value;import cn.thinkinjava.design.pattern.extend.pipeline.context.PipelineContext;/*** 管道中的操作对象的具体实现** author qiuxianbao* date 2024/01/02*/
public class ForeTest1Value extends AbstractPipelineValue {Overrideprotected boolean doExecute(PipelineContext context) {// 比如设置了一些值context.set(PipelineContext.FOR_TEST, true);return true;}
}//
package cn.thinkinjava.design.pattern.extend.pipeline.value;import cn.thinkinjava.design.pattern.extend.pipeline.context.PipelineContext;/*** 管道中的操作对象的具体实现** author qiuxianbao* date 2024/01/02*/
public class ForeTest2Value extends AbstractPipelineValue {Overrideprotected boolean doExecute(PipelineContext context) {return true;}
}以下是管道操作
package cn.thinkinjava.design.pattern.extend.pipeline;import cn.thinkinjava.design.pattern.extend.pipeline.value.PipelineValue;
import cn.thinkinjava.design.pattern.extend.pipeline.context.PipelineContext;/*** 管道** 适用场景* 当你的数据流需要经过很多同等逻辑处理时可以考虑使用此套路便于后续扩展** author qiuxianbao* date 2024/01/02*/
public interface Pipeline {/*** 执行操作** param context 上下文即要处理的对象* return*/boolean invoke(PipelineContext context);/*** 添加操作** param value 管道中的操作对象* return*/boolean addValue(PipelineValue value);/*** 删除操作** param value 管道中的操作对象* return*/boolean removeValue(PipelineValue value);
}// 核心
package cn.thinkinjava.design.pattern.extend.pipeline;import cn.thinkinjava.design.pattern.extend.pipeline.value.PipelineValue;
import cn.thinkinjava.design.pattern.extend.pipeline.context.PipelineContext;
import lombok.extern.slf4j.Slf4j;import java.util.ArrayList;
import java.util.List;/*** 管道实现类** author qiuxianbao* date 2024/01/02*/
Slf4j
public class StandardPipeline implements Pipeline{private ListPipelineValue valueList new ArrayList();Overridepublic boolean invoke(PipelineContext context) {boolean result true;for (PipelineValue item : valueList) {try {result item.execute(context);if (!result) {log.error({}, execute is wrong, this.getClass().getSimpleName());}} catch (Exception e) {log.error(e.getMessage(), e);}}return result;}Overridepublic boolean addValue(PipelineValue value) {if (valueList.contains(value)) {return true;}return valueList.add(value);}Overridepublic boolean removeValue(PipelineValue value) {return valueList.remove(value);}
}以下为客户端
package cn.thinkinjava.design.pattern.extend.pipeline.client;import cn.thinkinjava.design.pattern.extend.pipeline.Pipeline;
import cn.thinkinjava.design.pattern.extend.pipeline.StandardPipeline;
import cn.thinkinjava.design.pattern.extend.pipeline.value.PipelineValue;
import cn.thinkinjava.design.pattern.extend.pipeline.context.PipelineContext;
import cn.thinkinjava.design.pattern.extend.pipeline.context.StandardPipelineContext;
import cn.thinkinjava.design.pattern.extend.pipeline.value.ForeTest1Value;
import cn.thinkinjava.design.pattern.extend.pipeline.value.ForeTest2Value;/*** 客户端** author qiuxianbao* date 2024/01/02*/
public class PipelineClient {public static void main(String[] args) {// 管道Pipeline pipeline new StandardPipeline();// 管道中对象PipelineValue foreTestValue new ForeTest1Value();PipelineValue graySwitchValue new ForeTest2Value();pipeline.addValue(foreTestValue);pipeline.addValue(graySwitchValue);// 上下文PipelineContext context new StandardPipelineContext();// 调用pipeline.invoke(context);System.out.println(context.get(PipelineContext.FOR_TEST));// ForeTest1Value start
// ForeTest1Value end
// ForeTest2Value start
// ForeTest2Value end
// true}
} 过滤器链模式
过滤器链既然是链那么就会有先后顺序。但它并不像前面说的管道那样前面执行完然后交给后面执行。它和管道是有区别的这里巧妙地运用到了this和索引。
管道模式是一层进来然后出去接着进行下一层。
// ForeTest1Value start
// ForeTest1Value end
// ForeTest2Value start
// ForeTest2Value end
过滤器链是从外到内一层一层都先进来然后再由内到外一层一层再出去。
// ForTest1Filter before 1704180891151
// ForTest2Filter before 1704180891151
// ForTest2Filter end 1704180891152
// ForTest1Filter end 1704180891152以下为操作对象假设的
package cn.thinkinjava.design.pattern.extend.filterchain.request;/*** author qiuxianbao* date 2024/01/02*/
public interface HttpRequest {
}//
package cn.thinkinjava.design.pattern.extend.filterchain.request;/*** author qiuxianbao* date 2024/01/02*/
public class StandardHttpRequest implements HttpRequest {
}
以下为过滤器对象
package cn.thinkinjava.design.pattern.extend.filterchain.filter;import cn.thinkinjava.design.pattern.extend.filterchain.FilterChain;
import cn.thinkinjava.design.pattern.extend.filterchain.request.HttpRequest;/*** 过滤器** author qiuxianbao* date 2024/01/02*/
public interface Filter {void doFilter(HttpRequest httpRequest, FilterChain filterChain);
}//
package cn.thinkinjava.design.pattern.extend.filterchain.filter;import cn.thinkinjava.design.pattern.extend.filterchain.FilterChain;
import cn.thinkinjava.design.pattern.extend.filterchain.request.HttpRequest;
import lombok.extern.slf4j.Slf4j;/*** author qiuxianbao* date 2024/01/02*/
Slf4j
public class ForTest1Filter implements Filter {Overridepublic void doFilter(HttpRequest httpRequest, FilterChain filterChain) {log.info({} before {}, this.getClass().getSimpleName(), System.currentTimeMillis());// 这里是重点filterChain.doFilter(httpRequest);log.info({} end {}, this.getClass().getSimpleName(), System.currentTimeMillis());}
}//
package cn.thinkinjava.design.pattern.extend.filterchain.filter;import cn.thinkinjava.design.pattern.extend.filterchain.FilterChain;
import cn.thinkinjava.design.pattern.extend.filterchain.request.HttpRequest;
import lombok.extern.slf4j.Slf4j;/*** author qiuxianbao* date 2024/01/02*/
Slf4j
public class ForTest2Filter implements Filter {Overridepublic void doFilter(HttpRequest httpRequest, FilterChain filterChain) {log.info({} before {}, this.getClass().getSimpleName(), System.currentTimeMillis());filterChain.doFilter(httpRequest);log.info({} end {}, this.getClass().getSimpleName(), System.currentTimeMillis());}
}
以下为过滤器链
package cn.thinkinjava.design.pattern.extend.filterchain;import cn.thinkinjava.design.pattern.extend.filterchain.request.HttpRequest;
import cn.thinkinjava.design.pattern.extend.filterchain.filter.Filter;/*** 拦截器链** 适用场景* 常见的web请求场景** author qiuxianbao* date 2024/01/02*/
public interface FilterChain {void doFilter(HttpRequest httpRequest);void addFilter(Filter filter);
}// 核心
package cn.thinkinjava.design.pattern.extend.filterchain;import cn.thinkinjava.design.pattern.extend.filterchain.request.HttpRequest;
import cn.thinkinjava.design.pattern.extend.filterchain.filter.Filter;import java.util.ArrayList;
import java.util.List;/*** author qiuxianbao* date 2024/01/02*/
public class StandardFilterChain implements FilterChain {private ListFilter filterList new ArrayList();private int currentIndex 0;Overridepublic void doFilter(HttpRequest httpRequest) {if (currentIndex filterList.size()) {return;}Filter filter filterList.get(currentIndex);currentIndex currentIndex 1;filter.doFilter(httpRequest, this);}Overridepublic void addFilter(Filter filter) {if (filterList.contains(filter)) {return;}filterList.add(filter);}
}
以下为客户端
package cn.thinkinjava.design.pattern.extend.filterchain.client;import cn.thinkinjava.design.pattern.extend.filterchain.FilterChain;
import cn.thinkinjava.design.pattern.extend.filterchain.StandardFilterChain;
import cn.thinkinjava.design.pattern.extend.filterchain.request.HttpRequest;
import cn.thinkinjava.design.pattern.extend.filterchain.request.StandardHttpRequest;
import cn.thinkinjava.design.pattern.extend.filterchain.filter.ForTest1Filter;
import cn.thinkinjava.design.pattern.extend.filterchain.filter.ForTest2Filter;/*** 客户端** author qiuxianbao* date 2024/01/02*/
public class FilterClient {public static void main(String[] args) {FilterChain filterChain new StandardFilterChain();filterChain.addFilter(new ForTest1Filter());filterChain.addFilter(new ForTest2Filter());HttpRequest request new StandardHttpRequest();filterChain.doFilter(request);//ForTest1Filter before 1704180891151//ForTest2Filter before 1704180891151//ForTest2Filter end 1704180891152//ForTest1Filter end 1704180891152}
} 事件分发模式
事件派发器分配事件谁满足了事件则会有相应的事件监听器去处理事件。 一句话抽象出来几个对象事件、事件监听器谁满足、怎么处理、事件的产生事件源、事件派发器能够拿到所有事件的监听器进行循环 以下为事件
package cn.thinkinjava.design.pattern.extend.eventdispatch.event;/*** 事件** author qiuxianbao* date 2024/01/02*/
public interface Event {/*** 事件名称** return*/String getName();
}//
package cn.thinkinjava.design.pattern.extend.eventdispatch.event;/*** author qiuxianbao* date 2024/01/02*/
public class EventForTest1 implements Event {Overridepublic String getName() {return getClass().getSimpleName();}
}//
package cn.thinkinjava.design.pattern.extend.eventdispatch.event;/*** author qiuxianbao* date 2024/01/02*/
public class EventFor2 implements Event {Overridepublic String getName() {return getClass().getSimpleName();}
}
以下为事件监听器
package cn.thinkinjava.design.pattern.extend.eventdispatch.listener;import cn.thinkinjava.design.pattern.extend.eventdispatch.event.Event;/*** 事件监听器处理事件** author qiuxianbao* date 2024/01/02*/
public interface EventListener {/*** 是否支持此事件** param event* return*/boolean supportEvent(Event event);/*** 处理事件** return*/boolean handlerEvent(Event event);
}//
package cn.thinkinjava.design.pattern.extend.eventdispatch.listener;import cn.thinkinjava.design.pattern.extend.eventdispatch.event.Event;
import lombok.extern.slf4j.Slf4j;/*** author qiuxianbao* date 2024/01/02*/
Slf4j
public class EventListenerForTest implements EventListener {Overridepublic boolean supportEvent(Event event) {return event.getName().contains(Test);}Overridepublic boolean handlerEvent(Event event) {log.info({} \t handler {}, this.getClass().getSimpleName(), event.getName());return true;}
}//
package cn.thinkinjava.design.pattern.extend.eventdispatch.listener;import java.util.ArrayList;
import java.util.List;/*** 事件监听器管理** author qiuxianbao* date 2024/01/02*/
public class EventListenerManager {private static ListEventListener eventListenerList new ArrayList();/*** 添加事件监听器** param eventListener* return*/public static boolean addEventListener(EventListener eventListener) {if (eventListenerList.contains(eventListener)) {return true;}return eventListenerList.add(eventListener);}/*** 移除事件监听器** param eventListener* return*/public static boolean removeEventListener(EventListener eventListener) {if (eventListenerList.contains(eventListener)) {return eventListenerList.remove(eventListener);}return true;}/*** 获取事件监听器** return*/public static ListEventListener getEventListenerList() {return eventListenerList;}}
以下为事件源
package cn.thinkinjava.design.pattern.extend.eventdispatch.source;import cn.thinkinjava.design.pattern.extend.eventdispatch.event.Event;/*** 事件源** author qiuxianbao* date 2024/01/02*/
public interface EventSource {/*** 发出事件** return*/Event fireEvent();
}//
package cn.thinkinjava.design.pattern.extend.eventdispatch.source;import cn.thinkinjava.design.pattern.extend.eventdispatch.event.Event;
import cn.thinkinjava.design.pattern.extend.eventdispatch.event.EventForTest1;
import lombok.extern.slf4j.Slf4j;/*** author qiuxianbao* date 2024/01/02*/
Slf4j
public class EventSourceForTest1 implements EventSource {Overridepublic Event fireEvent() {// 发出的就是具体的事件了Event event new EventForTest1();log.info({} \t fireEvent {}, this.getClass().getSimpleName(), event.getName());return event;}
}//
package cn.thinkinjava.design.pattern.extend.eventdispatch.source;import cn.thinkinjava.design.pattern.extend.eventdispatch.event.Event;
import cn.thinkinjava.design.pattern.extend.eventdispatch.event.EventFor2;
import lombok.extern.slf4j.Slf4j;/*** author qiuxianbao* date 2024/01/02*/
Slf4j
public class EventSourceFor2 implements EventSource {Overridepublic Event fireEvent() {Event event new EventFor2();log.info({} \t fireEvent {}, this.getClass().getSimpleName(), event.getName());return event;}
}
以下为事件派发器
package cn.thinkinjava.design.pattern.extend.eventdispatch;import cn.thinkinjava.design.pattern.extend.eventdispatch.event.Event;
import cn.thinkinjava.design.pattern.extend.eventdispatch.listener.EventListener;
import cn.thinkinjava.design.pattern.extend.eventdispatch.listener.EventListenerManager;
import org.apache.commons.collections.CollectionUtils;/*** 事件分发器** author qiuxianbao* date 2024/01/02*/
public class EventDispatcher {private EventDispatcher() {}/*** 分发事件** param event*/public static void dispatchEvent(Event event) {// 核心if (CollectionUtils.isNotEmpty(EventListenerManager.getEventListenerList())) {for (EventListener eventListener : EventListenerManager.getEventListenerList()) {if (eventListener.supportEvent(event)) {eventListener.handlerEvent(event);}}}}
}以下为客户端
package cn.thinkinjava.design.pattern.extend.eventdispatch.client;import cn.thinkinjava.design.pattern.extend.eventdispatch.EventDispatcher;
import cn.thinkinjava.design.pattern.extend.eventdispatch.listener.EventListenerManager;
import cn.thinkinjava.design.pattern.extend.eventdispatch.source.EventSource;
import cn.thinkinjava.design.pattern.extend.eventdispatch.source.EventSourceForTest1;
import cn.thinkinjava.design.pattern.extend.eventdispatch.source.EventSourceFor2;
import cn.thinkinjava.design.pattern.extend.eventdispatch.listener.EventListener;
import cn.thinkinjava.design.pattern.extend.eventdispatch.listener.EventListenerForTest;/*** author qiuxianbao* date 2024/01/02*/
public class EventClient {public static void main(String[] args) {// 创建事件监听器EventListener eventListener new EventListenerForTest();EventListenerManager.addEventListener(eventListener);// 创建事件源EventSource eventSource1 new EventSourceForTest1();EventSource eventSource2 new EventSourceFor2();// 发布事件EventDispatcher.dispatchEvent(eventSource1.fireEvent());EventDispatcher.dispatchEvent(eventSource2.fireEvent());// 11:50:17.029 [main] INFO cn.thinkinjava.design.pattern.extend.eventdispatch.source.EventSourceForTest1 - EventSourceForTest1 fireEvent EventForTest1
// 11:50:17.067 [main] INFO cn.thinkinjava.design.pattern.extend.eventdispatch.listener.EventListenerForTest - EventListenerForTest handler EventForTest1
// 11:50:17.077 [main] INFO cn.thinkinjava.design.pattern.extend.eventdispatch.source.EventSourceFor2 - EventSourceFor2 fireEvent EventFor2}
} 模板工厂模式
提到模板通常都是在抽象类中实现通用逻辑然后留出接口未实现的交给其子类实现。这里组合工厂工厂用于维护所有的处理器。 以下是处理器 工厂
package cn.thinkinjava.design.pattern.extend.templatefactory.handler.base;import cn.thinkinjava.design.pattern.extend.templatefactory.PiiContent;import java.lang.reflect.Field;/*** author qiuxianbao* date 2024/01/04*/
public interface PiiDomainFieldHandler {/*** 处理实际操作* 读----从PiiContent获取数据回填domain** param domain* param domainField* param piiContent* param T* return*/T extends Object boolean handlerRead(T domain, Field domainField, PiiContent piiContent);/*** 处理实际操作* 写----将domain中需要写入pii的字段数据写入PiiContent** param domain* param domainField* param piiContent* param T* return*/T extends Object boolean handlerWrite(T domain, Field domainField, PiiContent piiContent);/*** 当前处理器是否支持该领域对象** param domain* param domainField* param T* return*/T extends Object boolean isSupport(T domain, Field domainField);/*** 获取处理器对应的元信息** return*/String getPiiDomainMeta();
}//
package cn.thinkinjava.design.pattern.extend.templatefactory.handler.base;import cn.thinkinjava.design.pattern.extend.templatefactory.PiiContent;
import lombok.extern.slf4j.Slf4j;import java.lang.reflect.Field;/*** 模板方法* 通过抽象类实现** author qiuxianbao* date 2024/01/04*/
Slf4j
public abstract class PiiDomainFieldHandlerBase implements PiiDomainFieldHandler{Overridepublic T boolean handlerRead(T domain, Field domainField, PiiContent piiContent) {log.info({} handlerRead {}, this.getClass().getSimpleName(), domain.getClass().getSimpleName());return true;}Overridepublic T boolean handlerWrite(T domain, Field domainField, PiiContent piiContent) {log.info({} handlerWrite {}, this.getClass().getSimpleName(), domain.getClass().getSimpleName());return true;}
}//
package cn.thinkinjava.design.pattern.extend.templatefactory.handler;import cn.thinkinjava.design.pattern.extend.templatefactory.handler.base.PiiDomainFieldHandlerBase;
import lombok.extern.slf4j.Slf4j;import java.lang.reflect.Field;/*** author qiuxianbao* date 2024/01/04*/
Slf4j
public class ForTestSupportFieldHandler extends PiiDomainFieldHandlerBase {Overridepublic T boolean isSupport(T domain, Field domainField) {if (this.getClass().getSimpleName().equalsIgnoreCase(domain.getClass().getSimpleName())) {log.info({} is support, to do some business, this.getClass().getSimpleName());return true;}return false;}Overridepublic String getPiiDomainMeta() {return this.getClass().getSimpleName();}
}//
package cn.thinkinjava.design.pattern.extend.templatefactory.handler;import cn.thinkinjava.design.pattern.extend.templatefactory.handler.base.PiiDomainFieldHandlerBase;
import lombok.extern.slf4j.Slf4j;import java.lang.reflect.Field;/*** author qiuxianbao* date 2024/01/04*/
Slf4j
public class ForTestNotSupportFieldHandler extends PiiDomainFieldHandlerBase {Overridepublic T boolean isSupport(T domain, Field domainField) {if (this.getClass().getSimpleName().equalsIgnoreCase(domain.getClass().getSimpleName())) {log.info({} is support, to do some business, this.getClass().getSimpleName());return true;}return false;}Overridepublic String getPiiDomainMeta() {return this.getClass().getSimpleName();}
}//
package cn.thinkinjava.design.pattern.extend.templatefactory.handler;import cn.thinkinjava.design.pattern.extend.templatefactory.handler.base.PiiDomainFieldHandler;import java.util.ArrayList;
import java.util.List;/*** 工厂类* 手动添加处理器** author qiuxianbao* date 2024/01/04*/
public class PiiDomainFieldHandlerFactory {/*** 创建领域处理器** return*/public static ListPiiDomainFieldHandler createPiiDomainFieldHandler() {ListPiiDomainFieldHandler piiDomainFieldHandlerList new ArrayList();// 添加处理器piiDomainFieldHandlerList.add(new ForTestSupportFieldHandler());piiDomainFieldHandlerList.add(new ForTestNotSupportFieldHandler());return piiDomainFieldHandlerList;}
}
以下是上下文对象
package cn.thinkinjava.design.pattern.extend.templatefactory;import java.util.HashMap;
import java.util.Map;/*** 上下文对象** author qiuxianbao* date 2024/01/04*/
public class PiiContent {public static String FORTESTfortest;private MapString, Object piiDataMap new HashMap();private MapString, Object piiContextMap new HashMap();public void putPiiData(String domainFieldName, Object domainFieldValue) {piiDataMap.put(domainFieldName, domainFieldValue);}public Object getPiiData(String domainFieldName) {return piiDataMap.get(domainFieldName);}public void putPiiContext(String contextName, Object contextNameValue) {piiContextMap.put(contextName, contextNameValue);}public Object getPiiContext(String contextName) {return piiContextMap.get(contextName);}
}
以下是处理器注册器从工厂中拿出处理器对外提供处理操作
package cn.thinkinjava.design.pattern.extend.templatefactory;import cn.thinkinjava.design.pattern.extend.templatefactory.handler.PiiDomainFieldHandlerFactory;
import cn.thinkinjava.design.pattern.extend.templatefactory.handler.base.PiiDomainFieldHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** 处理器注册器** author qiuxianbao* date 2024/01/04*/
Slf4j
public class PiiHandlerRegistry {private static MapString, PiiDomainFieldHandler piiDomainFieldHandlerMap new HashMap();public static void putHandler(String piiDomainFieldName, PiiDomainFieldHandler piiDomainFieldHandler) {if (StringUtils.isEmpty(piiDomainFieldName)) {log.warn( piiDomainFieldName is null,continue);return;}if (piiDomainFieldHandler null) {log.warn(piiDomainFieldName piiDomainFieldHandler is null,continue);return;}if (!piiDomainFieldHandlerMap.containsKey(piiDomainFieldName)) {piiDomainFieldHandlerMap.put(piiDomainFieldName, piiDomainFieldHandler);}}public static T extends Object int handlerRead(T domain, Field domainField, PiiContent piiContent) {int num 0;for (Map.EntryString, PiiDomainFieldHandler piiDomainFieldHandlerEntry :piiDomainFieldHandlerMap.entrySet()) {if (piiDomainFieldHandlerEntry.getValue().isSupport(domain, domainField)) {piiDomainFieldHandlerEntry.getValue().handlerRead(domain, domainField, piiContent);}}return num;}public static T extends Object int handlerWrite(T domain, Field domainField, PiiContent piiContent) {int num 0;for (Map.EntryString, PiiDomainFieldHandler piiDomainFieldHandlerEntry :piiDomainFieldHandlerMap.entrySet()) {if (piiDomainFieldHandlerEntry.getValue().isSupport(domain, domainField)) {piiDomainFieldHandlerEntry.getValue().handlerWrite(domain, domainField, piiContent);}}return num;}public static MapString, PiiDomainFieldHandler getPiiDomainFieldHandlerMap() {return piiDomainFieldHandlerMap;}public static void init() {ListPiiDomainFieldHandler piiDomainFieldHandlerList PiiDomainFieldHandlerFactory.createPiiDomainFieldHandler();if (CollectionUtils.isNotEmpty(piiDomainFieldHandlerList)) {for (PiiDomainFieldHandler piiDomainFieldHandler :piiDomainFieldHandlerList) {putHandler(piiDomainFieldHandler.getPiiDomainMeta(), piiDomainFieldHandler);}}}
}
以下是客户端
package cn.thinkinjava.design.pattern.extend.templatefactory.client;import cn.thinkinjava.design.pattern.extend.templatefactory.PiiContent;
import cn.thinkinjava.design.pattern.extend.templatefactory.PiiHandlerRegistry;
import cn.thinkinjava.design.pattern.extend.templatefactory.handler.ForTestNotSupportFieldHandler;
import cn.thinkinjava.design.pattern.extend.templatefactory.handler.ForTestSupportFieldHandler;
import cn.thinkinjava.design.pattern.extend.templatefactory.handler.base.PiiDomainFieldHandler;import java.util.Map;/*** 客户端** author qiuxianbao* date 2024/01/04*/
public class PiiClient {public static void main(String[] args) {// 通过工厂把处理器放到Map中PiiHandlerRegistry.init();// 遍历处理器for (Map.EntryString, PiiDomainFieldHandler entryHandler :PiiHandlerRegistry.getPiiDomainFieldHandlerMap().entrySet()) {System.out.println(entryHandler.getKey() \t entryHandler.getValue().getPiiDomainMeta());}//PiiContent piiContent new PiiContent();piiContent.putPiiContext(PiiContent.FORTEST, PiiContent.FORTEST);// 请求处理System.out.println(ForTestSupportFieldHandler start);PiiHandlerRegistry.handlerRead(new ForTestSupportFieldHandler(), null, piiContent);System.out.println(ForTestSupportFieldHandler end);// 请求处理System.out.println(ForTestNotSupportFieldHandler start);PiiHandlerRegistry.handlerRead(new ForTestNotSupportFieldHandler(), null, piiContent);System.out.println(ForTestNotSupportFieldHandler end);}
}SPI模式
SPI核心就是ServiceLoader
package java.util;
public final class ServiceLoaderSimplements IterableS {private static final String PREFIX META-INF/services/;
} 以下为简单示例 1、resources目录下建META-INF/services目录 2、新建文件文件名为接口全路径名。文件内容为实现类的全路径名。 接口和实现类
package cn.thinkinjava.design.pattern.extend.spi.service;/*** author qiuxianbao* date 2024/01/02*/
public interface RemoteService {
}//
package cn.thinkinjava.design.pattern.extend.spi.service.impl;import cn.thinkinjava.design.pattern.extend.spi.service.RemoteService;/*** author qiuxianbao* date 2024/01/02*/
public class RemoteServiceImpl implements RemoteService {
} 工具类
package cn.thinkinjava.design.pattern.extend.spi;import java.util.HashMap;
import java.util.Map;/*** 存储策略依赖的服务, 统一管理** author qiuxianbao* date 2024/01/02*/
public class DependServiceRegistryHelper {private static MapString, Object dependManagerMap new HashMap();public static boolean registryMap(MapClass, Object dependManagerMap) {for (Map.EntryClass, Object dependEntry : dependManagerMap.entrySet()) {registry(dependEntry.getKey(), dependEntry.getValue());}return true;}public static boolean registry(Class cls, Object dependObject) {dependManagerMap.put(cls.getCanonicalName(), dependObject);return true;}public static Object getDependObject(Class cls) {return dependManagerMap.get(cls.getCanonicalName());}
}//
package cn.thinkinjava.design.pattern.extend.spi;import cn.thinkinjava.design.pattern.extend.spi.service.RemoteService;import java.util.Iterator;
import java.util.ServiceLoader;/*** SPI的方式加载** 说明* 1.resource文件夹下建 META-INF/services文件夹* 2.创建一个文件文件名为接口的全限定名文件内容为接口实现类的全限定名** author qiuxianbao* date 2024/01/02*/
public class SpiServiceLoaderHelper {public static RemoteService getProductPackageRemoteServiceInterface() {Object serviceCache DependServiceRegistryHelper.getDependObject(RemoteService.class);if (serviceCache ! null) {return (RemoteService) serviceCache;}RemoteService serviceInterface loadSpiImpl(RemoteService.class);DependServiceRegistryHelper.registry(RemoteService.class, serviceInterface);return serviceInterface;}/*** 以spi的方式加载实现类** param cls* return*/private static P P loadSpiImpl(ClassP cls) {ServiceLoaderP spiLoader ServiceLoader.load(cls);IteratorP iterator spiLoader.iterator();if (iterator.hasNext()) {return iterator.next();}throw new RuntimeException(SpiServiceLoaderHelper loadSpiImpl failed, please check spi service);}}以下为客户端
package cn.thinkinjava.design.pattern.extend.spi.client;import cn.thinkinjava.design.pattern.extend.spi.SpiServiceLoaderHelper;
import cn.thinkinjava.design.pattern.extend.spi.service.RemoteService;/*** author qiuxianbao* date 2024/01/02*/
public class SPIClient {public static void main(String[] args) {RemoteService remoteService SpiServiceLoaderHelper.getProductPackageRemoteServiceInterface();System.out.println(remoteService);// cn.thinkinjava.main.extend.spi.service.impl.ProductPackageRemoteServiceInterfaceImpl2752f6e2}
}注解模式
通过添加注解可以进行一些扩展操作。 比如可以把所有加过注解的类通过Map缓存中再进行反射处理。 TcpMapping TcpMappingScan TcpFinder
以下是一个简单示例
package cn.thinkinjava.design.pattern.extend.annotation;import org.springframework.stereotype.Component;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 用于测试的标识注解** author qiuxianbao* date 2024/01/04*/
Target({ElementType.TYPE, ElementType.METHOD})
Retention(RetentionPolicy.RUNTIME)
Component
public interface ForTestAnnotation {
}//
package cn.thinkinjava.design.pattern.extend.annotation;/*** 代测试的Bean** author qiuxianbao* date 2024/01/04*/
ForTestAnnotation
public class ForTestBean {public ForTestBean() {System.out.println(ForTestBean.class.getSimpleName() init);}}//
package cn.thinkinjava.design.pattern.extend.annotation;import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;/*** 注解解析器** author qiuxianbao* date 2024/01/04*/
Component
public class ForTestAnnotationProcessor implements BeanPostProcessor {Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 获取目标类是否有ForTestAnnotation注解ForTestAnnotation annotation AnnotationUtils.findAnnotation(AopUtils.getTargetClass(bean),ForTestAnnotation.class);if (annotation null) {return bean;}// 处理想要的扩展System.out.println(beanName has ForTestAnnotation);return bean;}Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
}//
package cn.thinkinjava.design.pattern.extend.annotation.client;import org.springframework.context.annotation.AnnotationConfigApplicationContext;/*** 客户端** author qiuxianbao* date 2024/01/04*/
public class ForTestClient {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext new AnnotationConfigApplicationContext(cn.thinkinjava.main.extend.annotation);System.out.println(ForTestClient.class.getSimpleName());}} 其他
… 三、参考资料
《Java 中保持扩展性的几种套路和实现》 写在后面 如果本文内容对您有价值或者有启发的话欢迎点赞、关注、评论和转发。您的反馈和陪伴将促进我们共同进步和成长。 系列文章
【GitHub】- design-pattern设计模式