设计模式在SpringBoot开发中的应用

990 阅读4分钟

设计模式应该是每位程序员的必修课,随手百度一下,也能查到很多介绍设计模式的文章。 这边我整理了一些设计模式在我们SpringBoot开发中的应用

1 策略模式

  • 意图
    • 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换
  • 主要解决
    • 在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护
  • 何时使用
    • 一个系统有许多许多类,而区分它们的只是他们直接的行为
  • 如何解决
    • 将这些算法封装成一个一个的类,任意地替换
  • 关键代码
    • 实现同一个接口

定义一个接口

public interface IFileStrategy {

    /**
     * 属于哪种文件解析类型
     */
    FileTypeResolveEnum gainFileType();

    /**
     * 封装的公用算法(具体的解析方法)
     *
     * @param objectparam
     */
    void resolve(Object objectparam);

}

定义两种实现

@Component
public class AFileResolve implements IFileStrategy {


    @Override
    public FileTypeResolveEnum gainFileType() {
        return FileTypeResolveEnum.File_A_RESOLVE;
    }

    @Override
    public void resolve(Object objectparam) {
        System.out.println("A 类型解析文件,参数:" + objectparam);
        //A类型解析具体逻辑
    }

}
@Component
public class BFileResolve implements IFileStrategy {


    @Override
    public FileTypeResolveEnum gainFileType() {
        return FileTypeResolveEnum.File_B_RESOLVE;
    }

    @Override
    public void resolve(Object objectparam) {
        System.out.println("B 类型解析文件,参数:" + objectparam);
        //B类型解析具体逻辑
    }

}

使用时,把所有实现放到一个 map 里

可以理解为一个简易的工厂,工厂模式着重于对象的创建,策略模式则是着重于对象的实现

@Service
public class StrategyService {

    private final Map<FileTypeResolveEnum, IFileStrategy> map = new ConcurrentHashMap<>();

    @Autowired
    private StrategyService(List<IFileStrategy> list) {
        list.forEach(strategyService -> map.put(strategyService.gainFileType(), strategyService));
    }

    public void resolveFile(FileTypeResolveEnum fileTypeResolveEnum, Object objectParam) {
        IFileStrategy iFileStrategy = map.get(fileTypeResolveEnum);
        if (iFileStrategy != null) {
            iFileStrategy.resolve(objectParam);
        }
    }

}

2 责任链模式

  • 意图
    • 避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止
  • 主要解决
    • 职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了
  • 何时使用
    • 在处理消息的时候以过滤很多道
  • 如何解决
    • 拦截的类都实现统一接口
  • 关键代码
    • Handler 里面聚合它自己,在 HandlerRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去

定义一个抽象类

public abstract class AbstractHandler {

    //责任链中的下一个对象
    private AbstractHandler nextHandler;

    /**
     * 责任链的下一个对象
     */
    public void setNextHandler(AbstractHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    /**
     * 具体参数拦截逻辑,给子类去实现
     */
    public void filter(HttpServletRequest request, HttpServletResponse response) {
        doFilter(request, response);
        if (getNextHandler() != null) {
            getNextHandler().filter(request, response);
        }
    }

    public AbstractHandler getNextHandler() {
        return nextHandler;
    }

    abstract void doFilter(HttpServletRequest filterRequest, HttpServletResponse response);

}

定义三个实现类

@Component
@Order(1)
public class FirstFilter extends AbstractHandler {

    @Override
    void doFilter(HttpServletRequest filterRequest, HttpServletResponse response) {
        System.out.println("first filter");
    }
}
@Component
@Order(2)
public class SecondFilter extends AbstractHandler {

    @Override
    void doFilter(HttpServletRequest filterRequest, HttpServletResponse response) {
        System.out.println("second filter");
    }
}
@Component
@Order(-1)
public class ThirdFilter extends AbstractHandler {

    @Override
    void doFilter(HttpServletRequest filterRequest, HttpServletResponse response) {
        System.out.println("third filter");
    }
}

使用时,建立链式关系

@Service
public class ChainService {

    private AbstractHandler abstractHandler;

    @Autowired
    private ChainService(List<AbstractHandler> list) {
        for (int i = 0; i < list.size(); i++) {
            if (i == 0) {
                abstractHandler = list.get(0);
            } else {
                AbstractHandler currentHandler = list.get(i - 1);
                AbstractHandler nextHandler = list.get(i);
                currentHandler.setNextHandler(nextHandler);
            }
        }
    }

    public HttpServletResponse exec(HttpServletRequest request, HttpServletResponse response) {
        abstractHandler.filter(request, response);
        return response;
    }

    public AbstractHandler getAbstractHandler() {
        return abstractHandler;
    }

    public void setAbstractHandler(AbstractHandler abstractHandler) {
        this.abstractHandler = abstractHandler;
    }


}

3 模板模式

  • 意图
    • 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
  • 主要解决
    • 一些方法通用,却在每一个子类都重新写了这一方法
  • 何时使用
    • 有一些通用的方法
  • 如何解决
    • 将这些通用算法抽象出来
  • 关键代码
    • 在抽象类实现,其他步骤在子类实现

定义一个抽象模板类

public abstract class AbstractTemplate {

    abstract void step1();

    abstract void step2();

    abstract void step3();

    abstract String getType();

    public void handle() {
        step1();
        step2();
        step3();
    }
}

定义两个模板实现

@Component
@Order(1)
public class FirstTemplate extends AbstractTemplate {

    @Override
    void step1() {
        System.out.println("吃饭");
    }

    @Override
    void step2() {
        System.out.println("睡觉");
    }

    @Override
    void step3() {
        System.out.println("打豆豆");
    }

    @Override
    String getType() {
        return "first";
    }
}
@Component
@Order(2)
public class SecondTemplate extends AbstractTemplate {

    @Override
    void step1() {
        System.out.println("打豆豆");
    }

    @Override
    void step2() {
        System.out.println("吃饭");
    }

    @Override
    void step3() {
        System.out.println("睡觉");
    }

    @Override
    String getType() {
        return "second";
    }
}

使用时与策略模式类似

@Service
public class TemplateService {

    private Map<String, AbstractTemplate> map = new HashMap<>();

    @Autowired
    private TemplateService(List<AbstractTemplate> list) {
        list.forEach(abstractTemplate -> map.put(abstractTemplate.getType(), abstractTemplate));
    }


    public void handle(String type) {
        // 这边可以结合策略模式
        map.get(type).handle();
    }

}

4 观察者模式

  • 意图
    • 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新
  • 主要解决
    • 一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作
  • 何时使用
    • 一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知药"可吃
  • 如何解决
    • 使用面向对象技术,可以将这种依赖关系弱化
  • 关键代码
    • 在抽象类里有一个 ArrayList 存放观察者们

借助 guvava 的 EventBus

public class EventBusCenter {

    private static EventBus eventBus = new EventBus();

    public static EventBus getInstance() {
        return eventBus;
    }

    //添加观察者
    public static void register(Object obj) {
        eventBus.register(obj);
    }

    //移除观察者
    public static void unregister(Object obj) {
        eventBus.unregister(obj);
    }

    //把消息推给观察者
    public static void post(Object obj) {
        eventBus.post(obj);
    }

}

添加两种类型的订阅

public class EventListener {

    //加了订阅,这里标记这个方法是事件处理方法
    @Subscribe
    public void handle(NotifyEvent notifyEvent) {
        System.out.println("发送IM消息" + notifyEvent.getImNo());
        System.out.println("发送短信消息" + notifyEvent.getMobileNo());
        System.out.println("发送Email消息" + notifyEvent.getEmailNo());
    }
}
public class StringListener {

    //加了订阅,这里标记这个方法是事件处理方法
    @Subscribe
    public void handle(String text) {
        System.out.println("收到消息" + text);
    }
}
@Service
public class ObserverService {

    @PostConstruct
    public void init() {
        EventListener eventListener = new EventListener();
        StringListener stringListener = new StringListener();
        EventBusCenter.register(eventListener);
        EventBusCenter.register(stringListener);
    }

    public void handle() {
        // 会根据类型来
        EventBusCenter.post("1");
        EventBusCenter.post(new NotifyEvent("156********", "11@qq.com", "1"));
    }

}