前陣子專案內需要抽換原本共用類別庫的功能並引用third party的dll,但不希望改動原本主程式的程式碼,筆記以下兩種:
- 動態繫結
- 依賴注入DI(Unity framework)
類別庫與主程式的低耦合可以選用的做法。
因為是付費的third party套件不好列出來舉例,這邊我們改舉cache的案例,假設專案內有兩個快取(cache)機制選擇,
- System.Runtime.Caching(Process內)
- Microsoft.ApplicationServer.Caching(可以跨機器)
每次都是主程式實體化new Runtime或Appfabric類別起來使用cache,由於耦合程度較高(緊密耦合),當想抽換底層library只用其中一種 cache機制時,就會需要改動所有使用到的主程式,此時可以動態決定使用類別class來保持軟體彈性變得很重要。
A.動態繫結:
1.首先新增一個類別庫專案,新增一組介面ICache定義: 給主程式入口的介面共有Add/Remove/Get/Update 4個方法
public interface ICache
{
void Add(string key, object value);
void Remove(string key);
Object Get(string key);
void Update(string key, object value);
}
2.接著在同一個類別庫專案分別撰寫2個Class實作ICache的方法:
RuntimeMemory.cs
class RuntimeMemoryCache : ICache
{
private static ObjectCache cache = new MemoryCache("RuntimeMemoryCache");
public void Add(string key, object value)
{
if (value == null) { return; };
CacheItemPolicy oPolicy = new CacheItemPolicy();
oPolicy.AbsoluteExpiration = DateTime.Now.AddMinutes(1440);
cache.Add(key, value, oPolicy, null);
}
public void Remove(string key)
{
cache.Remove(key, null);
}
public object Get(string key)
{
return cache.Get(key, null);
}
public void Update(string key, object value)
{
cache.Set(key, value, null, null);
}
}
AppFabricCache.cs
class AppFabricCache : ICache
{
private DataCacheFactory factory;
private DataCache cache;
public AppFabricCache()
{
factory = new DataCacheFactory();
cache = factory.GetCache("cardcache");
}
public void Add(string key, object value)
{
if (value == null) { return; };
cache.Add(key, value);
cache.ResetObjectTimeout(key,new TimeSpan(365,23,29,59));
}
public void Remove(string key)
{
cache.Remove(key);
}
public object Get(string key)
{
return cache.Get(key);
}
public void Update(string key, object value)
{
cache.Put(key, value);
}
}
以上第1、2步不管採用動態繫結或是注入都是相同的,寫介面(interface)是很重要的設計。
3.組態config檔案內容設定要載入的class。
<appSettings>
<!--<add key="CacheClass" value="(放class的namespace).RuntimeMemoryCache"/>-->
<add key="CacheClass" value="(放class的namespace).AppFabricCache"/>
</appSettings>
4.主程式引用類別庫,然後依據組態Config參數使用反射+動態載入ICache介面的方式:
這樣程式的維護以及程式單元測試變得容易一些。
下一篇筆記 採用DI注入的方式來解決動態載入class需求(使用unity framework)
參考:
Unity Framework: How to Instantiate two classes from the same Interface?
Reflection and Dynamic Class Loading