Service Locator 模式
什麼是Service Locator 模式?
服務定位模式(Service Locator Pattern)是一種軟體開發中的設計模式,透過應用強大的抽象層,可對涉及嘗試獲取一個服務的過程進行封裝。該模式使用一個稱為"Service Locator"的中心登錄檔來處理請求並返回處理特定任務所需的必要資訊。
場景描述
某類ClassA依賴於服務ServiceA和服務ServiceB,服務的具體型別需在編譯時指定。
這種條件下有以下缺點:
嘗試替換或更新依賴項,必須更改類的原始碼並且重新編譯。
依賴項的具體實現必須在編譯時可用。
測試該類非常困難,因為類對依賴項有直接的引用,則依賴項不能使用Stub或Mock物件替換。
該類包含用於建立、定位和管理依賴項的重複程式碼。
設計目標
使用 Service Locator Pattern 來達成以下目標:
把類與依賴項解耦,從而使這些依賴項可被替換或者更新。
類在編譯時並不知道依賴項的具體實現。
類的隔離性和可測試性非常好。
類無需負責依賴項的建立、定位和管理邏輯。
透過將應用程式分解為松耦合的模組,達成模組間的無依賴開發、測試、版本控制和部署。
解決方案
建立一個 Service Locator,其包含各服務的引用,並且封裝了定位服務的邏輯。在類中使用 Service Locator 來獲取所需服務的例項。
Service Locator 模式並不描述如何例項化服務,其描述了一種註冊和定位服務的方式。通常情況下,Service Locator 模式與工廠模式(Factory Pattern)和依賴注入模式(Dependency Injection Pattern)等結合使用。
服務定位器應該能夠在不知道抽象類的具體型別的情況下定位到服務。例如,它可能會使用字串或服務介面型別來影射服務,這允許在無需修改類的條件下替換依賴項的具體實現。
實現細節
通常 ServiceLocator 類提供 IServiceLocator 介面的實現單例,並負責管理該例項的建立和訪問。ServiceLocator 類提供 IServiceLocator 介面的預設實現,例如 ActivatingServiceLocator 類,可以同時建立和定位服務。
注意事項
在使用 Service Locator 模式之前,請考慮以下幾點:
有很多程式中的元素需要管理。
在使用之前必須編寫額外的程式碼將服務的引用新增到服務定位器。
類將對服務定位器有依賴關係。
原始碼變的更加複雜和難以理解。
可以使用配置資料來定義執行時的關係。
必須提供服務的實現。因為服務定位器模式將服務消費者與服務提供者解耦,它可能需要提供額外的邏輯。這種邏輯將保證在服務消費者嘗試定位服務之前,服務提供者已被安裝和註冊。
相關模式
依賴注入(Dependency Injection)。這種模式解決了與 Service Locator 模式相同的問題,但它使用不同的方法。
控制反轉(Inversion of Control)。Service Locator 模式是這種模式的特殊版本。它將應用程式的傳統控制流程反轉。它用被呼叫物件來代替控制過程的呼叫方。
參考資訊
Inversion of Control and the Dependency Injection pattern on Martin Fowler's Web site
Service Locator on MSDN
程式碼示例
Service Locator 的簡單實現,使用靜態類實現,未使用Singleton設計,僅作Mapping影射。
using System; using System.Collections.Generic; using System.Globalization; using System.Reflection; namespace Infrastructure { ////// 服務定位器 /// public static class ServiceLocator { #region Fields private static readonly Dictionary_mapping = new Dictionary (); private static readonly Dictionary _resources = new Dictionary (); private static object _operationLock = new object(); #endregion #region Add /// /// 新增註冊資源 /// ///資源型別 /// 資源例項 public static void Add(object instance) where TClass : class { Add(typeof(TClass), instance); } /// /// 新增註冊資源 /// /// 資源型別 /// 資源例項 public static void Add(Type typeOfInstance, object instance) { if (typeOfInstance == null) throw new ArgumentNullException("typeOfInstance"); if (instance == null) throw new ArgumentNullException("instance"); if (!(typeOfInstance.IsInstanceOfType(instance))) { throw new InvalidCastException( string.Format(CultureInfo.InvariantCulture, "Resource does not implement supplied interface: {0}", typeOfInstance.FullName)); } lock (_operationLock) { if (_resources.ContainsKey(typeOfInstance)) { throw new ArgumentException( string.Format(CultureInfo.InvariantCulture, "Resource is already existing : {0}", typeOfInstance.FullName)); } _resources[typeOfInstance] = instance; } } #endregion #region Get ////// 查詢指定型別的資源例項 /// ///資源型別 ///資源例項 public static TClass Get() where TClass : class { return Get(typeof(TClass)) as TClass; } /// /// 查詢指定型別的資源例項 /// /// The type of instance. ///資源例項 public static object Get(Type typeOfInstance) { if (typeOfInstance == null) throw new ArgumentNullException("typeOfInstance"); object resource; lock (_operationLock) { if (!_resources.TryGetValue(typeOfInstance, out resource)) { throw new ResourceNotFoundException(typeOfInstance.FullName); } } if (resource == null) { throw new ResourceNotInstantiatedException(typeOfInstance.FullName); } return resource; } ////// 嘗試查詢指定型別的資源例項 /// ///資源型別 /// 資源例項 ///是否存在指定資源型別的資源例項 public static bool TryGet(out TClass resource) where TClass : class { bool isFound = false; resource = null; object target; lock (_operationLock) { if (_resources.TryGetValue(typeof(TClass), out target)) { resource = target as TClass; isFound = true; } } return isFound; } #endregion #region Register /// /// 註冊型別 /// ///實體型別,型別限制為有公共無參建構函式 public static void RegisterType() where TClass : class, new() { lock (_operationLock) { _mapping[typeof(TClass)] = typeof(TClass); } } /// /// 註冊型別 /// ///資源型別 ///實體型別,型別限制為有公共無參建構函式 public static void RegisterType() where TFrom : class where TTo : TFrom, new() { lock (_operationLock) { _mapping[typeof(TFrom)] = typeof(TTo); _mapping[typeof(TTo)] = typeof(TTo); } } /// /// 是否已註冊此型別 /// ///資源型別 ///是否已註冊此型別 public static bool IsRegistered() { lock (_operationLock) { return _mapping.ContainsKey(typeof(TClass)); } } #endregion #region Resolve /// /// 獲取型別例項 /// ///資源型別 ///型別例項 public static TClass Resolve() where TClass : class { TClass resource = default(TClass); bool existing = TryGet (out resource); if (!existing) { ConstructorInfo constructor = null; lock (_operationLock) { if (!_mapping.ContainsKey(typeof(TClass))) { throw new ResourceNotResolvedException( string.Format(CultureInfo.InvariantCulture, "Cannot find the target type : {0}", typeof(TClass).FullName)); } Type concrete = _mapping[typeof(TClass)]; constructor = concrete.GetConstructor( BindingFlags.Instance | BindingFlags.Public, null, new Type[0], null); if (constructor == null) { throw new ResourceNotResolvedException( string.Format(CultureInfo.InvariantCulture, "Public constructor is missing for type : {0}", typeof(TClass).FullName)); } } Add ((TClass)constructor.Invoke(null)); } return Get (); } #endregion #region Remove /// /// 移除指定型別的資源例項 /// ///資源型別 public static void Remove() { Teardown(typeof(TClass)); } /// /// 移除指定型別的資源例項 /// /// 資源型別 public static void Remove(Type typeOfInstance) { if (typeOfInstance == null) throw new ArgumentNullException("typeOfInstance"); lock (_operationLock) { _resources.Remove(typeOfInstance); } } #endregion #region Teardown ////// 拆除指定型別的資源例項及註冊對映型別 /// ///資源型別 public static void Teardown() { Teardown(typeof(TClass)); } /// /// 拆除指定型別的資源例項及註冊對映型別 /// /// 資源型別 public static void Teardown(Type typeOfInstance) { if (typeOfInstance == null) throw new ArgumentNullException("typeOfInstance"); lock (_operationLock) { _resources.Remove(typeOfInstance); _mapping.Remove(typeOfInstance); } } #endregion #region Clear ////// 移除所有資源 /// public static void Clear() { lock (_operationLock) { _resources.Clear(); _mapping.Clear(); } } #endregion } }
Service Locator 測試程式碼
using System; using Infrastructure; namespace ServiceLocatorTest { class Program { interface IServiceA { string GetData(); } class ServiceA : IServiceA { public string GetData() { return "This data is from ServiceA"; } } static void Main(string[] args) { ServiceLocator.RegisterType(); IServiceA serviceA = ServiceLocator.Resolve (); string data = serviceA.GetData(); Console.WriteLine(data); Console.ReadKey(); } } }
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1762/viewspace-2800869/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Service Mesh模式起源模式
- 如何使用 Service 模式模式
- 關於Selenium裡如何設計Locator
- 雲設計模式和Service Mesh設計模式
- 報錯求助:Unsupported locator strategy: -ios predicate stringiOS
- Laravel 設計模式:Repository + Service 實戰Laravel設計模式
- Android基礎知識:Service(3)啟動模式Android模式
- Angular應用架構設計-2:Data Service模式Angular應用架構模式
- 深入 K8s 網路原理(二)- Service iptables 模式分析K8S模式
- OneThink的Ucenter沒有寫完,我想用service模式沒法用模式
- Service
- Android ServiceAndroid
- k8s之Service詳解-Service使用K8S
- Android Intent ServiceAndroidIntent
- systemd service unit
- 深入掌握service
- Service Worker初探
- Android Service SecurityAndroid
- What is a service mesh?
- Service詳解
- 建立windows serviceWindows
- 教程|使用Istio實現一個Service Mesh以簡化微服務間的通訊模式微服務模式
- Android Service生命週期 Service裡面的onStartCommand()方法詳解Android
- 【應用服務 App Service】App Service 新手資料包APP
- Service呼叫其他Service的private方法, @Transactional會生效嗎(上)
- 【Azure Bot Service】部署Python ChatBot程式碼到App Service中PythonAPP
- Service啟動流程
- Service銷燬流程
- 認識 Service Worker
- Guide to Database as a Service (DBaaS)GUIIDEDatabase
- Alexa Voice Service 概述
- 清晰地理解Service
- 8.2 Service3
- 2.4.1 Service Creation in a CDB
- Spring Web Service教程SpringWeb
- Service Mesh 介紹
- Laravel 2.3 Service ProviderLaravelIDE
- Angular service 詳解Angular