防腐層模式
與遺留舊系統整合是一個無趣的荒路,這已不是什麼秘密:糟糕的文件,缺乏支援,雜亂的介面以及少數幾個錯誤只是在整合過程中可能遇到的問題的一個子集。然而,出於技術和/或政治原因,整合是絕對必要的。與遺留系統的整合會對設計中的系統造成風險,因為傳統模型通常設計不當,會對你新設計良好的模型很可能被遺留整合破壞。
整合策略
防腐層Anti-Corruption是一種高度防禦性的策略,可以透過傳統模型將您的模型與腐敗隔離開來。防腐層結合了一組模式:門面facade模式和介面卡模式。將模型與其需要整合的其他模型隔離開來。
如果兩個模型之間存在Customer-Supplier關係,則防腐層可能是單向的,或者是雙向的。
為了說明這種模式,我們首先考慮一個電子商務應用程式,它透過估計傳送訂單所需的包的數量和尺寸來顯示訂單的運輸成本,然後使用複雜的網路遍歷演算法來查詢最便宜的運輸路線。由此我們可以快速推斷出兩個不同的背景:運輸和包裝,每個都有不同的功能和完全獨立的模型。
事實證明,該公司已經擁有多年使用的傳統包裝服務 - 因為該組織之前專注於包裝行業,然後才將戰略轉向電子商務。當架構師仔細研究傳統的包裝服務時,他們意識到與傳統的整合是不可避免的,因為服務非常複雜(表明許多知識已經被遺留下來),因此放棄遺產或大規模嘗試更換舊系統是笨重的解決方案。仔細研究也排除了一種完全依舊使用舊系統的方法,因為遺留模型已經過時,並不再適合當前的商業模式。
遺憾的是,打包服務太舊,沒有文件記錄,並且因為許多錯誤而臭名昭著,這些錯誤迫使系統中的其他元件進行了多次臨時的解決方案實施,此外,編寫該服務的原始開發人員已離開組織,運輸團隊完全只能靠自己。此時,架構師決定將運輸上下文與包裝上下文整合在一起,防腐層將運輸模型與遺留模式隔離開來。
讓我們仔細研究傳統的包裝模型,才能瞭解其突出模型的弱點以及它們如何破壞運輸模型:
namespace Warehouse.Packaging { public class Container { //Irrelevant details } public class Package { public double LengthInInches { get; } public double WidthInInches { get; } public double HeightInInches { get; } } public class Item { public double LengthInInches { get; } public double WidthInInches { get; } public double HeightInInches { get; } } public class Warehouse { public string Code { get; } public string ZipCode { get; } public IEnumerable<Container> AvailableContainers { get; } //Further details of a messy model } public interface ILegacyPackagingService { bool ValidateItemDimensions (IEnumerable<Item> items); IEnumerable<Package> PackageItems (IEnumerable<Item> items, Warehouse warehouse); IEnumerable<Package> OptimizePackaging (IEnumerable<Package> packages); } } |
上述領域模型存在以下幾個問題:
1- ILegacyPackagingService提供了一個複雜的介面,其中驗證,打包和最佳化作為三個單獨的API提供 - 可能有很好的理由 - 但是這不符合運輸Shipping模型的需要,因為從運輸角度看,所有這一系列操作可被視為一個單獨的操作。
2- Item和Package模型使用英制測量系統,這與所有新模型中採用公制系統的新組織範圍政策存在衝突。
3-Package模組中的倉庫模型高度過時,不再反映業務如何為自己的倉庫建模。
4- PackageItems定義的API:ILegacyPackagingService引入了包裝邏輯和Warehouse模型之間的耦合- 因為包裝預設被視為只能在公司的指定倉庫中進行的操作。但是,目前的Shipping模型無法維持這樣的假設前提,因為它允許產品直接從外部供應商的倉儲設施發貨。
外觀facade模式
顯然,防腐層有很多工作要做。把任何上述問題洩漏到Shipping模型中將產生損壞的模型,該模型承載遺留系統的所有弱點。為了緩解第一個問題,我們在防腐層中引入了一個外觀facade:
namespace Warehouse.Packaging.AntiCorruption.Shipping { public interface IPackagingServiceFacade { IEnumerable<Warehouse.Packaging.Package> PackageItems (IEnumerable<Item> items, Warehouse warehouse); } public class PackagingServiceFacade : IPackagingServiceFacade { private readonly ILegacyPackagingService _packagingService; public PackagingServiceFacade (ILegacyPackagingService packagingService) { _packagingService = packagingService; } public IEnumerable<Warehouse.Packaging.Package> PackageItems (IEnumerable<Item> items, Warehouse warehouse) { if (_packagingService.ValidateItemDimensions (items)) { var packages = _packagingService.PackageItems (items, warehouse); var optimizedPackages = _packagingService.OptimizePackaging (packages); return optimizedPackages; } return Enumerable.Empty<Package> (); } } } |
請注意,Façade使用了與Packaging服務相同的模型,未新增任何模型元素,語言風格被保持下來聊。Façade僅為模型提供了更友好的介面。Façade自己甚至位於Warehouse.Packaging模組/名稱空間下,包含Packaging上下文(防腐層可以跨越多個模組)。
轉換器translator模式
為了解決第二個問題,防腐層將定義一個轉換器物件,這樣在兩個上下文中使用的不同模型之間進行對映,在下面的示例中,我們使用AutoMapper以簡單的方式說明對映操作:
namespace Logistics.Shipping.AntiCorruption.Packaging { public class PackagerProfile : Profile { private const double InchesCmConversionConst = 0.39370; public PackagerProfile() { CreateMap<Product, Item>() .ForMember(dst => dst.LengthInInches, opt => opt.MapFrom(src => src.LengthInCm * InchesCmConversionConst)) .ForMember(dst => dst.WidthInInches, opt => opt.MapFrom(src => src.WidthInCm * InchesCmConversionConst)) .ForMember(dst => dst.HeightInInches, opt => opt.MapFrom(src => src.HeightInCm * InchesCmConversionConst)); CreateMap<Warehouse.Packaging.Package, Logistics.Shipping.Package>() .ForMember(dst => dst.LengthInCm, opt => opt.MapFrom(src => src.LengthInInches / InchesCmConversionConst)) .ForMember(dst => dst.WidthInCm, opt => opt.MapFrom(src => src.WidthInInches / InchesCmConversionConst)) .ForMember(dst => dst.HeightInCm, opt => opt.MapFrom(src => src.HeightInInches / InchesCmConversionConst)); } } } |
可以來回使用轉換器來對映不相容的模型。
介面卡Adapter模式
為了處理第三個和第四個問題,我們向防腐層引入了一個介面卡,它為Shipping運輸服務提供了一個更相容的介面,該介面與Warehouse模型鬆散耦合,而是使用Containervalue物件來表示包裝功能:
namespace Logistics.Shipping.AntiCorruption.Packaging { public interface IPackagingService { IEnumerable<Logistics.Shipping.Package> PackageItems (IEnumerable<Product> items, IEnumerable<Container> containers); } public class PackagingServiceAdapter : IPackagingService { private readonly IPackagingServiceFacade _packagingServiceFacade; private readonly IMapper _mapper; public PackagingServiceAdapter (IPackagingServiceFacade packagingServiceFacade, IMapper mapper) { _packagingServiceFacade = packagingServiceFacade; _mapper = mapper; } public IEnumerable<Logistics.Shipping.Package> PackageItems (IEnumerable<Product> products, IEnumerable<Container> containers) { Warehouse warehouse; //Logic to initialize a transient dummy warehouse var items = _mapper.Map<IEnumerable<Item>> (products); //Using the translator to map the Product model to an Item var packages = _packagingServiceFacade.PackageItems (items, warehouse); //Calling the Façade return _mapper.Map<IEnumerable<Logistics.Shipping.Package>> (packages); //Mapping the Packager's result to the Package model defined in the Shipping context } } } |
與傳統打包服務整合的Shipping模型,不會受到遺留損壞:
namespace Logistics.Shipping { public class Zone { } public class Product { public double LengthInCm { get; } public double WidthInCm { get; } public double HeightInCm { get; } } public class Package { public double LengthInCm { get; } public double WidthInCm { get; } public double HeightInCm { get; } } public class Courier { private IPackagingService _packagingService; public double GetQuote (IEnumerable<Product> items, Zone source, Zone destination) { var packagingCapabilities = _capabilitiesService.GetPackagingCapabilities (source); var packages = _packagingService.PackageItems (items, packagingCapabilities.Containers); //Shipping specific logic goes here } } } |
結論
開發防腐層是一個耗時的過程,需要大量的分析和開發工作。架構師不應該立刻跳到這個解決方案,而是首先考慮其他簡單的替代方案,但是當沒有其他選擇時,防腐層 - 就像圍繞堡壘的牆壁進行入侵 - 將保護您的模型免受外部影響並讓你獨立地工作。
相關文章
- DDD領域驅動設計架構模式:防腐層(Anti-corruption layer)架構模式
- .NET應用架構設計—使用者端的防腐層作用及設計應用架構
- VRA-LM防腐塗料汙水處理廠防腐施工中需要注意的事項ZTOVR
- 二層交換機埠模式模式
- WRF設定模式垂直層模式
- Photoshop圖層模式詳解(轉)模式
- 層模式——面向模式體系結構學習筆記模式筆記
- 新定義三層,指揮官模式模式
- 橋接模式:探索JDBC底層實現橋接模式JDBC
- 二層網路資料轉發模式模式
- Seata原始碼分析(一). AT模式底層實現原始碼模式
- Photoshop圖層混合模式計算公式大全(轉)模式公式
- 平谷模式,AI賦能基層的「樣板間」模式AI
- 設計模式:與SpringMVC底層息息相關的介面卡模式設計模式SpringMVC
- 九層天塔智慧合約模式系統開發模式
- asp.net標準三層架構--工廠模式ASP.NET架構模式
- 讓港珠澳大橋如此長壽的祕訣:先進的防腐蝕技術
- 基層衛生健康雲HIS系統原始碼 SaaS模式原始碼模式
- 【設計模式】第九篇:組合模式解決層級關係結構問題設計模式
- 分散式系統中的解耦模式:隔離事件層 - mathiasverraes分散式解耦模式事件
- 9、如何理解應用層、傳輸層、網路層、鏈路層、物理層
- 三層網路結構(核心層、匯聚層 、接入層)
- 編碼風格:Mvc模式下SSM環境,程式碼分層管理MVC模式SSM
- 應用層和驅動如何判斷當前的啟動模式模式
- 關於資料庫的資料獨立性及三層模式資料庫模式
- JAVA中Action層, Service層 ,model層 和 Dao層的功能區分Java
- 軟考之路(六)---資料庫---深入淺出 三層模式兩級映像資料庫模式
- 基層管理漫談(2):東瞧西看,瞭解管理模式(轉)模式
- 網路是七層、五層還是四層?
- 網路的四層五層七層網路
- 軟體架構設計原則和模式(上):分層架構設計架構模式
- tour cpp: std::variant 實現無繼承層次的訪問者模式繼承模式
- 三層架構及分層架構
- 手淘雙11最新實踐:PopLayer彈層領域業務研發模式升級模式
- 也談TDD,以及三層架構、設計模式、ORM……:沒有免費的午餐架構設計模式ORM
- Saas模式資料庫層資料架構以及資料刪除處理 (轉)模式資料庫架構
- 轉享:表現層架構模式比較:MVP(SC),MVP(PV),PM,MVVM 和 MVC架構模式MVPMVVMMVC
- 總結!計網分層 每層任務 每層協議協議