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

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

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.xdnf.cn/news/879211.html

相关文章:

  • Angular报错:cann‘t bind to ngClass since it is‘t a known property of div
  • Spring Boot 缓存注解详解:@Cacheable、@CachePut、@CacheEvict(超详细实战版)
  • Monorepo架构: Nx Cloud 扩展能力与缓存加速
  • [华为eNSP] OSPF综合实验
  • 在不同型号的手机或平板上后台运行Aidlux
  • 4.3 HarmonyOS NEXT AI驱动的交互创新:智能助手、实时语音与AR/MR开发实战
  • 时序数据库IoTDB的UDF Sample算法在数据监控、故障预防的应用
  • 高并发内存池的轻量级模拟-主体部分:分析拆解多线程内存管理难题
  • Neo4j 完全指南:从入门到精通
  • 文档处理组件Aspose.Words 25.5全新发布 :六大新功能与性能深度优化
  • 《doubao-lite-32k 模型缓存机制使用指南》
  • npm install 相关命令
  • 04-初识css
  • 阿里云ACP云计算备考笔记 (3)——云存储RDS
  • Java转Go日记(六十):gin其他常用知识
  • Python实现markdown文件转word
  • C# ExcelWorksheet 贴图
  • WordZero:让Markdown与Word文档自由转换的Golang利器
  • 云原生 DevOps 实践路线:构建敏捷、高效、可观测的交付体系
  • Java在word中指定位置插入图片。
  • idea json生成实体类
  • XTEA与TEA的区别
  • Git 安装全攻略Linux、macOS、Windows 与源码编译
  • 【hadoop】Flink安装部署
  • 如何利用Haption力反馈遥操作机器人解决远程操作难题
  • 【西门子杯工业嵌入式-2-点亮一颗LED】
  • bug 记录 - 使用 el-dialog 的 before-close 的坑
  • 【HarmonyOS 5】 影视与直播详以及 开发案例
  • 跑通 TrackNet-Badminton-Tracking-tensorflow2 项目全记录
  • 鸿蒙缺少WMIC missing WMIC