作者:京东科技 倪新明
门面模式和适配器模式是代码级的设计模式,而防腐层本质是一种 防御型策略 ,在更高的层级对系统进行解耦
Anti-Corruption Layer(ACL) 如下:
Implement a façade or adapter layer between different subsystems that don't share the same semantics . This layer translates requests that one subsystem makes to the other subsystem. Use this pattern to ensure that an application's design is not limited by dependencies on outside subsystems .
在不共享语义的不同子系统间实现一个门面层或适配层,该层转换一个系统到另一个子系统的请求,使用该模式确保一个应用的设计不被外部系统的依赖所限制。
一个系统不可能承担所有的职能,大多数情况下都会依赖外部系统的数据或能力。这些外部系统或者遗留系统所关注的领域以及技术选型不尽相同,特别是对于一些老旧的遗留系统往往会面临是技术升级或淘汰的场景。所以,新系统与老系统间的集成往往需要适配他们的协议、数据模型、API或者某些功能特性,但是对于设计人员并不总是希望将这些方面的 “渗入” 到当前系统中。这种情况不仅仅出现在新系统和遗留系统之间,对于系统所依赖的第三方系统也同样适用,因为这些第三方系统可能存在由不同团队开发、技术选型及架构各异、领域模型不一致、可控性差等等诸多不可控因素。
上述场景在实际的业务开发中经常遇到,我们构建的系统并不是孤立的,而是会融入到公司现有的IT系统,甚至会依赖公司外部的三方服务,形式上可能基于HTTP协议的调用,也可能是内部的JSF或OPEN-API调用。这种场景下,外部系统服务提供的模型与内部系统领域上下文下的模型不能确保保持一致。如果在系统设计时不考虑隔离,而是将外部模型直接穿透到内部系统的核心域,则当模型语义产生不一致,或发生变化时,会污染自身领域。
建立防腐层对不同的子系统进行隔离,该层负责转换两个子系统间的通信。通过引入防腐层,实现不同子系统间的解耦,隔离外部系统的变化对当前系统的影响,避免当前系统的设计由于外部系统的设计和技术实现方式而进行妥协。

防腐层一般会包括模型转换的职能:
• 将当前系统的模型转换成外部系统的模型
• 将外部系统的响应转换成当前系统的模型

除此之外,通过在不同子系统间引入独立的 "层",可以在该层进行例如:
• 外部系统调用进行统一监控
• 对多个子系统的门面封装
• 对模型转换的适配
• 外部调用失败的降级处理
• 统一缓存机制
• .....
防腐层模式适用于:
• 如果老系统迁移至新的系统需要多个迁移阶段,但是依然要维护新系统和老系统间的集成
• 两个或更多子系统间存在不同的语义,但是依然需要相互通信
需要说明的是,如果两个系统间没有特别大的语义差异可能不太适合防腐层模式。也就是说,存在与外部系统交互的场景不一定非要使用防腐层模式,对于模型稳定、语义一致的场景,则没有必要引入额外的一层进行隔离。
Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use .

门面模式在当前系统和外部系统之间引入了“薄薄的一层”,实现了客户端与外部复杂子系统或组件的解耦,但其并不是降低了系统的复杂性,相应的,它只是对客户端屏蔽了外部系统的复杂性,使得客户端访问子系统更加简单。
• 门面类的职能并不应该对子系统接口的返回数据模型进行封装,其只是负责简化对子系统接口的访问。
• 门面模式并不是对所有的子系统接口都进行覆盖,按需即可
• 门面类不局限于一个,例如,有多个子系统,可以按实际情况建立多个门面类
• 子系统感知不到门面类的存在,而门面类则需要感知各个子系统
• 门面类和子系统耦合,子系统接口的变更会影响到门面类的变更
Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.
通过适配器模式实现两个不兼容接口的无缝集成:

适配器模式本质上适配器模式所承担的职责应该是 "不多不少",只要满足不兼容接口的适配能力即可。
适配器模式目标类和适配者类解耦,易于扩展,符合SOLID的开闭原则,同时,也提高了对已有类的复用性。但,和其他的设计模式一样,适配器模式也会引入额外的类,在一定程度上也会增加系统的复杂性,同样也会增加对代码的认知负载。
门面模式和适配器模式是代码级的设计模式,而防腐层本质是一种防御型策略,在更高的层级对系统进行解耦。通常情况下,防腐层包含一系列的门面类和适配器类以及一些转换器类。
• 门面模式对外部系统接口进行简单封装以便更易使用
• 适配器模式负责进行内部系统与外部系统的模型兼容
• 转换器负责对扩系统的模型进行转换
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende
给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最
电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。 准备工作: 1、U盘一个(尽量使用8G以上的U盘)。 2、一台正常联网可使用的电脑。 3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。 4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。 U盘启动盘制作步骤: 注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc
了解Rails缓存如何工作的人可以真正帮助我。这是嵌套在Rails::Initializer.runblock中的代码:config.after_initializedoSomeClass.const_set'SOME_CONST','SOME_VAL'end现在,如果我运行script/server并发出请求,一切都很好。然而,在我的Rails应用程序的第二个请求中,一切都因单元化常量错误而变得糟糕。在生产模式下,我可以成功发出第二个请求,这意味着常量仍然存在。我已通过将以上内容更改为以下内容来解决问题:config.after_initializedorequire'some_cl
因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实
在Ruby中,以毫秒为单位获取自纪元(1970)以来的当前系统时间的正确方法是什么?我试过了Time.now.to_i,好像不是我想要的结果。我需要结果显示毫秒并且使用long类型,而不是float或double。 最佳答案 (Time.now.to_f*1000).to_iTime.now.to_f显示包含十进制数字的时间。要获得毫秒数,只需将时间乘以1000。 关于ruby-以毫秒为单位获取当前系统时间,我们在StackOverflow上找到一个类似的问题: