写在前面
  偶然间看到一篇文章 《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 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
    }
}
模板+工厂模式
提到模板,通常都是在抽象类中实现通用逻辑,然后留出接口未实现的交给其子类实现。这里组合工厂,工厂用于维护所有的处理器。

 以下是处理器 + 工厂,
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());
    }
}
其他
…
三、参考资料
《Java 中保持扩展性的几种套路和实现》
写在后面
如果本文内容对您有价值或者有启发的话,欢迎点赞、关注、评论和转发。您的反馈和陪伴将促进我们共同进步和成长。
系列文章
【GitHub】- design-pattern(设计模式)
 



















