知识卡片

插件:把散落各工厂的环境判断收拢成运行时可配置的单点

普通读书笔记卡

内容

当应用要在多个环境下运行、每个环境对同一行为需要不同实现时(比如主键生成器,单元测试用内存计数器、生产环境用数据库序列),常见做法是写工厂方法、在里面用条件判断检查当前处于哪种环境来决定返回哪个实现。问题在工厂一多就会变得一团糟:新建一种部署配置组合(比如”内存数据库+无事务的单测模式”或”DB2数据库+完整事务的生产模式”),往往要同时修改散落在好几个工厂里的条件判断逻辑,然后重新编译部署——配置本该是一件集中、轻量的事,结果却被摊薄进了整个代码库,还绑上了重新编译这道门槛。插件模式的解法:先用分离接口定义好所有”不同环境需要不同实现”的行为,再造一个插件工厂,但要求接口到具体实现的连接规则写在代码之外的一个独立地方(通常是文本配置文件),并且这个连接必须在运行时动态完成,而不是编译时——这样换配置只需要改配置文件,不用碰代码、也不用重新编译部署。如果语言支持反射,插件工厂可以做得完全通用:配置文件直接存”接口名→实现类名”的映射,工厂读取配置后用反射动态构造出实现对象,即便日后新增实现类,工厂代码本身都不用改;即使语言不支持反射,插件模式依然有价值——只是这时工厂内部还是要写条件判断把接口映射到具体实现,代价是每新增一种实现类都要往工厂里加一个分支,但好处仍然在于把这个判断集中到了唯一一个地方,而不是散落进多个工厂各自维护。可迁移启发:”配置该往哪里配”和”要不要重新编译”其实是两个可以分开设计的维度——即便暂时用不上反射带来的完全免代码扩展,把原本散落多处的环境判断集中收拢到一个地方、并让连接规则本身可以脱离代码单独调整,已经能大幅降低新增部署配置的成本。

参考来源

- 位置:《企业应用架构模式》第二部分"模式"之"第18章 基本模式"之"18.9 插件"(源文件:_epub-src/OEBPS/Text/000233.html) - 结论依据:原文说明"当你有数个工厂以后,你的手头就会变得一团糟。建立一个新的部署配置……需要在多个工厂中修改条件语句,然后重新编译和部署……插件工厂要求指明某一环境下,接口与哪一个实现连接的指令在一个单独的、代码之外的地方进行声明……与实现的连接必须是在运行时动态进行,而不是在编译时进行,这样才能在重配置后无需重新编译",直接支撑本卡结论。 - 原始内容:即使没有使用支持反射机制的程序语言,插件仍然有其存在的价值,它创建了一个中心配置点。