1 設計模式 類是我們面向對象編程的承載工具,可以說是面向對象的起點。 設計模式,這種算面向對象的進化。按照gof設計模式的分類 設計模式分為:創建型,結構型,行為型。 其中創建型主要和類的創建有關 結構性組織擴展類和類之間的關係 行為型主要擴展的類的訪問 這三個對應到類上 創建型模式對應的是構造函 ...
1 設計模式
類是我們面向對象編程的承載工具,可以說是面向對象的起點。
設計模式,這種算面向對象的進化。按照gof設計模式的分類
設計模式分為:創建型,結構型,行為型。
其中創建型主要和類的創建有關
結構性組織擴展類和類之間的關係
行為型主要擴展的類的訪問
這三個對應到類上
創建型模式對應的是構造函數
結構型對應的是類的屬性
行為型對應類的方法
就想我們以前學數學中很多證明題,都源自最基本的定理,面向對象編程也有類似的地方
設計模式就是類最基本功能的一個進化
2.依賴註入
相信大家對Ioc(依賴註入)肯定不陌生,Ioc主要遵循設計原則中的依賴倒置原則,
但是假設我們不要把這個東西提升到設計的高度,只看它的功能就會發現, Ioc創建類正好就是控制類的構造函數,和設計模式中創建型模式有關,
例如創建型模式中單例模式用ioc生命周期管理可以達到同樣的效果,
這裡以Unity為例,Untiy支持child容器。利用child容器,我們可以在運行時提供更多動態創建的內容。
我們以asp.net mvc為例,我們可以在session初始化的時候根據不同用戶註入不同介面的實現。
例如我們可以在repository中註入一個預設的規約,當不同用戶登錄 我們可以將用戶對數據的訪問許可權形成一個規約,
註冊到child容器中,然後在controller激活的時候使用當前session的子容器來激活controller。
在這裡使用例子中,Ioc又實現了類似factory,甚至是building模式的功能(這個例子會在後面的文章中給大家展現具體的實現).
3.抽象的維度
多態是代碼的下行
抽象是代碼的下行
如果B繼承自A,C繼承自A,那麼A稱之為B,C這個維度的抽象,B,C稱之為A這個維度的變化 A,B,C稱之為一個維度的繼承關係
傳統的繼承解決的是一個維度的變化,如果我們在這個維度上面引入泛型,並且用where限制泛型的行為 或者屬性,
那麼就可以用諸如interface<T1,T2,T3>這樣,通過組合幾個泛型提供多個維度的變化。 此處用泛型擴展的繼承有點類似於多繼承。
4.元數據編程(Attribute)
Attribute在我所使用的元數據編程占有重要位置。
在asp.net mvc中,ValueProvider,ModuleBinding,Validator,Filter,都使用了元數據編程。
不談這個大的我們看一個更小的例子。
最早在winform中使用DateGrid的時候,我們都是在grid設計器中去設置列的屬性,名稱,綁定的欄位,等等。
如果我們引入元數據編程,就可以通過在類的屬性上加上特性來擴展。
這樣做更便於維護,當你的界面需要修改時,只需要在綁定的類上做修改,修改的地方相對集中,而不用去操作設計器。
5. 策略工廠
上面說了很多理論的東西,下麵為大家帶來點乾貨。
首先我們分析一個簡單工廠的代碼:
public interface ITest { void DoSomething(); } public class Test1: ITest { public void DoSomething() { } } public class Test2: ITest { public void DoSomething() { } } public class Factory { public static ITest Create(string type) { if (type == "1") return new Test1(); if (type == "2") return new Test2(); throw new NotImplementedException(); } }
分析簡單工廠的弊端
1,擴展不方便需要改動create的邏輯
2,客戶需要知道create的具體邏輯
3,創建類型過於單一導致簡單工廠類的泛濫
4,無法為對象創建提供靈活性,例如構造函數參數
5,無法實現運行時擴展
下麵我對簡單工廠做了一些改造
public interface IStrategy { } public interface IGenericsFactory<TStrategy> where TStrategy : IStrategy { /// <summary> /// 註冊處理策略 /// </summary> /// <param name="name"></param> /// <returns></returns> void Regist(Type type); /// <summary> /// 獲取處理策略 /// </summary> /// <param name="name"></param> /// <returns></returns> TStrategy GetStrategy(string name); /// <summary> /// 獲取所有的處理策略 /// </summary> /// <param name="name"></param> /// <returns></returns> List<string> GetStrategys(); } public class GenericsFactory<TStrategy> : IGenericsFactory<TStrategy> where TStrategy : IStrategy { public GenericsFactory() { if (_strategys == null) { _strategys = GetType().Assembly .GetTypes() .Where(item => item.GetInterfaces().Contains(typeof(TStrategy)) || item.IsSubclassOf(typeof(TStrategy))) .Where(item => !item.IsAbstract) .ToDictionary(item => { var desc = item.GetCustomAttribute<DescriptionAttribute>(); return desc != null ? desc.Description : string.Empty; }, item => item); } } protected Dictionary<string, Type> _strategys; public void Regist(Type type) { if (type.GetInterfaces().Contains(typeof(TStrategy)) && type.IsSubclassOf(typeof(TStrategy))) throw new TypeLoadException(string.Format("類型不是從{0},繼承",typeof(TStrategy).Name)); if (_strategys.ContainsKey(MetaDataManager.Attribute.GetDescription(type))) return; _strategys.Add(MetaDataManager.Attribute.GetDescription(type), type); } public TStrategy GetStrategy(string name) { if (!_strategys.ContainsKey(name)) _strategys.Add(name, typeof(TStrategy)); return (TStrategy)UnityService.Resolve(_strategys[name]); } public List<string> GetStrategys() { return _strategys.Keys.ToList(); } }
改造思路
1,使用將create的類型標記在對應的介面實現上,反射獲取子類的特性,如果新增加一個類型只
需要增加子類,並且在子類添加特性
2,將所有可用子類的元素據緩存起來,在工廠構造函數中反射所有子類和子類的特性用字典緩存起來
並且所有可創建的類型暴露給外部
3,將構造出來的類型做成泛型,並且提供泛型限制,將可構造類型獨立出一個維度來變化
4,通過ioc來動態創建類型
5,通過提供regist來提供運行時擴展
使用的案例:
1,SSO登陸,前臺用戶和後臺用戶,存放在不同的數據表,數據結構也可能不一樣
2,動態數據許可權配置,例如,某個角色只能訪問某部分數據 =,>,<等等這些篩選條件的擴展
3,狀態者模式,狀態可擴展,可以由界面去選擇某種狀態對應那種處理方式,
將處理方式類型放在資料庫
4,責任鏈模式中節點的擴展和配置
通過緩存可以直接所有節點,靈活配置節點來實現流程的功能
5,裝飾器的擴展
可以搭配裝飾器模式配置出先用某個裝飾後用某個裝飾、
總結:
上面的這些關於程式設計的一些思考,會在後面的文章中分享一些自己在實際項目中的
具體案例,請關註後續文章。要想一個架構設計能順利推廣,最簡單粗暴的方法就是這個架構能夠幫助程式員少些代碼。
下一篇文章將分享一個,全棧式編程的設計,主要應用於後臺系統的增刪改查,方便程式員更
快速的處理掉數據的增刪改查這部分通用邏輯