写在前面
偶然间看到一篇文章 《Java 中保持扩展性的几种套路和实现》,写的不错,但是类图画的差了点儿意思。于是,自己动手画了画,对其中的内容作了一些调整,对包做了进一步划分,便于理解消化
。以下是对GitHub项目 design-pattern-extend 的快览,后期将新的套路慢慢补充。
一、项目结构
以下为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 Map<String, Object> contextMap = new HashMap<>();
@Override
public void set(String contextKey, Object contextValue) {
contextMap.put(contextKey, contextValue);
}
@Override
public 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 {
@Override
public 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 {
@Override
protected 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 {
@Override
protected 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 List<PipelineValue> valueList = new ArrayList<>();
@Override
public 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;
}
@Override
public boolean addValue(PipelineValue value) {
if (valueList.contains(value)) {
return true;
}
return valueList.add(value);
}
@Override
public 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 {
@Override
public 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 {
@Override
public 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 List<Filter> filterList = new ArrayList<>();
private int currentIndex = 0;
@Override
public void doFilter(HttpRequest httpRequest) {
if (currentIndex == filterList.size()) {
return;
}
Filter filter = filterList.get(currentIndex);
currentIndex = currentIndex + 1;
filter.doFilter(httpRequest, this);
}
@Override
public 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 {
@Override
public String getName() {
return getClass().getSimpleName();
}
}
//
package cn.thinkinjava.design.pattern.extend.eventdispatch.event;
/**
* @author qiuxianbao
* @date 2024/01/02
*/
public class EventFor2 implements Event {
@Override
public 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 {
@Override
public boolean supportEvent(Event event) {
return event.getName().contains("Test");
}
@Override
public 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 List<EventListener> 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 List<EventListener> 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 {
@Override
public 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 {
@Override
public 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
}
}
以下是一个真实场景Netty客户端接收数据的示例,代码中运用到了 “事件派发” + “工厂(参数转换器)”。简单说一下思路,具体代码请前往GitHub自行查找。
在Netty服务端下发指令后,客户端可以根据不同的指令进行相应的逻辑处理。
由于客户端入口只有一个TcpClientHandler#channelRead0,但是逻辑有很多个。这个时候,就可以用事件派发模式。
把不同逻辑组装起来统一管理,然后在入口处,根据不同的指令调用不同的操作。本质上解决是if...else的问题。
核心:
1.自定义注解@TcpMapping,用于实现不用的逻辑
2.定义TcpMappingScan用于收集@TcpMapping,进行统一管理
3.调用是从统一管理处取出,通过反射操作
模板+工厂模式
提到模板,通常都是在抽象类中实现通用逻辑,然后留出接口未实现的交给其子类实现。这里组合工厂,工厂用于维护所有的处理器。
以下是处理器 + 工厂,
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{
@Override
public <T> boolean handlerRead(T domain, Field domainField, PiiContent piiContent) {
log.info("{} handlerRead {}", this.getClass().getSimpleName(), domain.getClass().getSimpleName());
return true;
}
@Override
public <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 {
@Override
public <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;
}
@Override
public 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 {
@Override
public <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;
}
@Override
public 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 List<PiiDomainFieldHandler> createPiiDomainFieldHandler() {
List<PiiDomainFieldHandler> 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 FORTEST="fortest";
private Map<String, Object> piiDataMap = new HashMap<>();
private Map<String, 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 Map<String, 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.Entry<String, 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.Entry<String, PiiDomainFieldHandler> piiDomainFieldHandlerEntry :
piiDomainFieldHandlerMap.entrySet()) {
if (piiDomainFieldHandlerEntry.getValue().isSupport(domain, domainField)) {
piiDomainFieldHandlerEntry.getValue().handlerWrite(domain, domainField, piiContent);
}
}
return num;
}
public static Map<String, PiiDomainFieldHandler> getPiiDomainFieldHandlerMap() {
return piiDomainFieldHandlerMap;
}
public static void init() {
List<PiiDomainFieldHandler> 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.Entry<String, 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 ServiceLoader<S>
implements Iterable<S> {
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 Map<String, Object> dependManagerMap = new HashMap<>();
public static boolean registryMap(Map<Class, Object> dependManagerMap) {
for (Map.Entry<Class, 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(Class<P> cls) {
ServiceLoader<P> spiLoader = ServiceLoader.load(cls);
Iterator<P> 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.ProductPackageRemoteServiceInterfaceImpl@2752f6e2
}
}
注解模式
通过添加注解,可以进行一些扩展操作。
比如:可以把所有加过注解的类通过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 {
@Override
public 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;
}
@Override
public 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());
}
}
其他
…
三、参考资料
写在后面
如果本文内容对您有价值或者有启发的话,欢迎点赞、关注、评论和转发。您的反馈和陪伴将促进我们共同进步和成长。
系列文章
【GitHub】- design-pattern(设计模式)
原文地址:https://blog.csdn.net/u010773514/article/details/135411933
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_54268.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!