当前位置: 首页 > article >正文

【设计模式】门面/外观模式

MySQL ,MyTomcat 的启动

现在有 MySQL ,MyTomcat 类,需要依次启动。

public class Application {public static void main(String[] args) {MySQL mySQL = new MySQL();mySQL.initDate();mySQL.checkLog();mySQL.unlock();mySQL.listenPort();MyTomcat myTomcat = new MyTomcat();myTomcat.initEngine();myTomcat.initWeb();}
}public class MySQL {void initDate(){System.out.println("初始化数据库");}void checkLog(){System.out.println("检查日志");}void unlock(){System.out.println("数据库解锁");}void listenPort(){System.out.println("监听端口");}
}public class MyTomcat {void initEngine(){System.out.println("初始化引擎");}void initWeb(){System.out.println("初始化Web应用");}
}

明明只是启动 MySQL,MyTomcat,mian 中却 调用了很多个方法。

于是你 定义了 一个接口 ServiceFacade,实现了这个接口的,必须实现其中的 start()

public interface ServiceFacade {void start();
}

于是你改造了 你的 MySQL,MyTomcat

public interface ServiceFacade {void start();
}public class MySQL implements ServiceFacade{void initDate(){System.out.println("初始化数据库");}void checkLog(){System.out.println("检查日志");}void unlock(){System.out.println("数据库解锁");}void listenPort(){System.out.println("监听端口");}// 实现 start()@Overridepublic void start() {initDate();checkLog();unlock();listenPort();}
}public class MyTomcat implements ServiceFacade{void initEngine(){System.out.println("初始化引擎");}void initWeb(){System.out.println("初始化Web应用");}// 实现 start()@Overridepublic void start() {initEngine();initWeb();}
}// -------------------------------------------
public class Application {public static void main(String[] args) {ServiceFacade mySQL = new MySQL();mySQL.start();ServiceFacade myTomcat = new MyTomcat();myTomcat.start();}
}

像这样:对外提供统一的接口,调用者不需要关心具体的实现。 这就是门面模式的核心。

插件遵循自己的门面

SLF4j、JDBC 都是设计一个门面,不同的人,有不同的实现方式。

这是比较著名的门面,大家都可以遵循。

而我们自己写的门面,如何让别人遵循,符合我们的规则呢 ?

思考:SpringBoot 打包时,会打包出一个 包含 Tomcat 的 jar 包,这个 jar 包是是谁帮助我们打包的呢?

  • SpringBoot 打包的。

问题:只不过是执行了 Maven 相关的命令,SpringBoot 为什么会打一个 jar 包呢?

  • SpringBoot 依赖 Maven 插件,Maven 插件实现了这个功能。
  • Maven 插件的 API ,就是 Maven 的门面。
  • 由此我们自己也可以写一个插件,定义自己的门面。

动手写一个插件

@RestController
public class TimeController {@GetMapping("/time")public String getTime(){return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss SSS"));}
}

这是一个 RestFul 接口,现在我要写一个插件,要求插件再 getTime() 前执行。

my_plugin_api 工程 插件的 API:

package insight.plugin;public interface MyPlugin {// 再 GetTime 执行前调用void beforeGetTime();
}

于是 RestFul 接口 变成:

@RestController
public class TimeController {MyPlugin myPlugin;@GetMapping("/time")public String getTime(){if (myPlugin != null){myPlugin.beforeGetTime();}return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss SSS"));}
}

问题:从哪里加载 myPlugin ?

  • 提供一个接口,用于 加载 插件
// 约定:实现了我的插件的jar包,必须有一个 wispx.plugin 文件。 
// 里面是实现 MyPlugin 的全类名。
@GetMapping("/loadPlug/{path}")
public String loadPlugin(@PathVariable("path") String path){File jarFile = new File(path);try (URLClassLoader classLoader = new URLClassLoader(new URL[]{jarFile.toURI().toURL()});InputStream wispxStream = classLoader.getResourceAsStream("wispx.plugin");){String className = new String(wispxStream.readAllBytes());Class<?> aClass = classLoader.loadClass(className);Constructor<?> constructor = aClass.getConstructor();myPlugin= (MyPlugin)constructor.newInstance();return "加载成功" + aClass.getName();}catch (Exception e){return "加载失败";}
}

实现 插件的工程:

public class CountPlugin implements MyPlugin{AtomicInteger count = new AtomicInteger(0);@Overridepublic void beforeGetTime() {System.out.println(count.incrementAndGet());}
}

打成 jar 包,在原先的工程中引入。

测试 插件

GET http://localhost:8080/timeGET http://localhost:8080/loadPlug/count_plugin-1.0-SNAPSHOT.jar

测试插件是否加载成功。

让 插件 加载到正在运行的程序中。

总结

定义一个插件,这就是 插件的门面。

第三方去实现插件。

通过一些约定把 插件 加载到正在运行的程序中。

思考

SpringBoot 自动装配 中的 springboot.factory 文件

gradle 的 build.gradle

tomcat 的 web.xml

Java 原生的 spi

http://www.lryc.cn/news/2401496.html

相关文章:

  • spring的webclient与vertx的webclient的比较
  • 贪心算法应用:埃及分数问题详解
  • 高效集成AI能力:使用开放API打造问答系统,不用训练模型,也能做出懂知识的AI
  • Qt 仪表盘源码分享
  • Python数据可视化科技图表绘制系列教程(四)
  • RPM 数据库修复
  • R语言基础知识总结(超详细整理)
  • 深入理解系统:UML类图
  • C# 中的 IRecipient
  • 大模型RNN
  • Python环境搭建竞赛技术文章大纲
  • Redisson - 实现延迟队列
  • 软件工程的定义与发展历程
  • 艾利特协作机器人:重新定义工业涂胶场景的精度革命
  • 第十三节:第五部分:集合框架:集合嵌套
  • Java设计模式之观察者模式详解
  • freeRTOS 消息队列之一个事件添加到消息队列超时怎么处理
  • 十八、【用户认证篇】安全第一步:基于 JWT 的前后端分离认证方案
  • RabbitMQ 开机启动配置教程
  • Authpf(OpenBSD)认证防火墙到ssh连接到SSH端口转发技术栈 与渗透网络安全的关联 (RED Team Technique )
  • 组合与排列
  • 神经网络-Day45
  • 【西门子杯工业嵌入式-1-基本环境与空白模板】
  • Apache Druid
  • 使用深蓝词库软件导入自定义的词库到微软拼音输入法
  • Docker快速部署AnythingLLM全攻略
  • 使用Node.js分片上传大文件到阿里云OSS
  • 高性能分布式消息队列系统(四)
  • C#异步编程:从线程到Task的进化之路
  • [论文阅读] 人工智能+软件工程 | 用大模型优化软件性能