DIP依賴倒置原則:系統架構時,高層模塊不應該依賴於低層模塊,二者通過抽象來依賴依賴抽象,而不是細節 貫徹依賴倒置原則,左邊能抽象,右邊實例化的時候不能直接用抽象,所以需要藉助一個第三方 高層本來是依賴低層,但是可以通過工廠(容器)來決定細節,去掉了對低層的依賴 IOC控制反轉:把高層對低層的依賴, ...
DIP依賴倒置原則:系統架構時,高層模塊不應該依賴於低層模塊,二者通過抽象來依賴
依賴抽象,而不是細節
貫徹依賴倒置原則,左邊能抽象,右邊實例化的時候不能直接用抽象,所以需要藉助一個第三方
高層本來是依賴低層,但是可以通過工廠(容器)來決定細節,去掉了對低層的依賴
IOC控制反轉:把高層對低層的依賴,轉移到第三方決定,避免高層對低層的直接依賴(是一種目的)
那麼程式架構就具備良好擴展性和穩定性
DI依賴註入:是用來實現IOC的一種手段,
在構造對象時,可以自動的去初始化,對象需要的對象
構造函數註入 屬性註入 方法註入,IOC容器初始化ApplePhone的時候 通過配置文件實例化 屬性,方法,構造函數
using Microsoft.Practices.Unity; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Ruanmou.Interface; using System; using Unity.Attributes; namespace Ruanmou.Service { public class ApplePhone : IPhone { [Dependency]//屬性註入:不錯,但是有對容器的依賴 public IMicrophone iMicrophone { get; set; } public IHeadphone iHeadphone { get; set; } public IPower iPower { get; set; } //[InjectionConstructor] public ApplePhone() { Console.WriteLine("{0}構造函數", this.GetType().Name); } //[InjectionConstructor]//構造函數註入:最好的,預設找參數最多的構造函數 public ApplePhone(IHeadphone headphone) { this.iHeadphone = headphone; Console.WriteLine("{0}帶參數構造函數", this.GetType().Name); } public void Call() { Console.WriteLine("{0}打電話", this.GetType().Name); } [InjectionMethod]//方法註入:最不好的,增加一個沒有意義的方法,破壞封裝 public void Init1234(IPower power) { this.iPower = power; } } }
不管是構造對象,還是註入對象,這裡都是靠反射做到的
有了依賴註入,才可能做到無限層級的依賴抽象,才能做到控制反轉
IOC Unity容器 可以通過代碼註冊或配置文件註冊介面對應實現類,實現了不依賴具體,可以對對象全局單例,線程單例
例子1
Service業務邏輯層升級,在原有1.0的基礎上添加一些功能,使用配置文件註冊
<container name="testContainer1"> <register type="Ruanmou.Interface.IPhone,Ruanmou.Interface" mapTo="Ruanmou.Service.ApplePhone, Ruanmou.Service"/> <register type="Ruanmou.Interface.IPhone,Ruanmou.Interface" mapTo="Ruanmou.Service.AndroidPhone, Ruanmou.Service" name="Android"/> <register type="Ruanmou.Interface.IMicrophone, Ruanmou.Interface" mapTo="Ruanmou.Service.Microphone, Ruanmou.Service"/> <register type="Ruanmou.Interface.IHeadphone, Ruanmou.Interface" mapTo="Ruanmou.Service.Headphone, Ruanmou.Service"/> <register type="Ruanmou.Interface.IPower, Ruanmou.Interface" mapTo="Ruanmou.Service.Power, Ruanmou.Service"/> <register type="Ruanmou.IDAL.IBaseDAL, Ruanmou.IDAL" mapTo="Ruamou.DAL.BaseDAL, Ruamou.DAL"/> </container> <container name="testContainer"> <register type="Ruanmou.Interface.IPhone,Ruanmou.Interface" mapTo="Ruanmou.Service.AndroidPhone, Ruanmou.Service.Extend"/> <register type="Ruanmou.Interface.IPhone,Ruanmou.Interface" mapTo="Ruanmou.Service.AndroidPhone, Ruanmou.Service.Extend" name="Android"/> <register type="Ruanmou.Interface.IMicrophone, Ruanmou.Interface" mapTo="Ruanmou.Service.Microphone, Ruanmou.Service.Extend"/> <register type="Ruanmou.Interface.IHeadphone, Ruanmou.Interface" mapTo="Ruanmou.Service.Headphone, Ruanmou.Service.Extend"/> <register type="Ruanmou.Interface.IPower, Ruanmou.Interface" mapTo="Ruanmou.Service.Power, Ruanmou.Service.Extend"/> <register type="Ruanmou.IDAL.IBaseDAL, Ruanmou.IDAL" mapTo="Ruamou.DAL.BaseDAL, Ruamou.DAL"/> </container>
只需要把服務2.0的類庫(實現1.0的原有介面)dll拿過來即可使用,代碼不做任何修改
例子2 業務擴展,新加功能
應該是加幾個介面和實現類的映射,就可以解決了。
例子3 實現AOP
方法需要加日誌,加異常管理,可以不修改原有代碼,直接新加異常管理類等的類庫,在Unity配置文件添加AOP配置節點即可實現
配置文件配置,
<container name="testContainerAOP"> <extension type="Interception"/> <register type="Ruanmou.Interface.IPhone,Ruanmou.Interface" mapTo="Ruanmou.Service.AndroidPhone, Ruanmou.Service.Extend"> <interceptor type="InterfaceInterceptor"/> <interceptionBehavior type="Ruanmou.Framework.AOP.AuthorizeBehavior, Ruanmou.Framework"/> <interceptionBehavior type="Ruanmou.Framework.AOP.SmsBehavior, Ruanmou.Framework"/> <interceptionBehavior type="Ruanmou.Framework.AOP.ExceptionLoggingBehavior, Ruanmou.Framework"/> <interceptionBehavior type="Ruanmou.Framework.AOP.CachingBehavior, Ruanmou.Framework"/> <interceptionBehavior type="Ruanmou.Framework.AOP.LogBeforeBehavior, Ruanmou.Framework"/> <interceptionBehavior type="Ruanmou.Framework.AOP.ParameterCheckBehavior, Ruanmou.Framework"/> <interceptionBehavior type="Ruanmou.Framework.AOP.LogAfterBehavior, Ruanmou.Framework"/> </register> <register type="Ruanmou.Interface.IPhone,Ruanmou.Interface" mapTo="Ruanmou.Service.AndroidPhone, Ruanmou.Service.Extend" name="Android"/> <register type="Ruanmou.Interface.IMicrophone, Ruanmou.Interface" mapTo="Ruanmou.Service.Microphone, Ruanmou.Service.Extend"/> <register type="Ruanmou.Interface.IHeadphone, Ruanmou.Interface" mapTo="Ruanmou.Service.Headphone, Ruanmou.Service.Extend"/> <register type="Ruanmou.Interface.IPower, Ruanmou.Interface" mapTo="Ruanmou.Service.Power, Ruanmou.Service.Extend"/> <register type="Ruanmou.IDAL.IBaseDAL, Ruanmou.IDAL" mapTo="Ruamou.DAL.BaseDAL, Ruamou.DAL"> </register> </container>
貼一個異常處理的AOP例子代碼
namespace Ruanmou.Framework.AOP { public class ExceptionLoggingBehavior : IInterceptionBehavior { public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { IMethodReturn methodReturn = getNext()(input, getNext); Console.WriteLine("ExceptionLoggingBehavior"); if (methodReturn.Exception == null) { Console.WriteLine("無異常"); } else { Console.WriteLine($"異常:{methodReturn.Exception.Message}"); } return methodReturn; } public bool WillExecute { get { return true; } } } }
例子4 數據訪問層的替換,因為已經不依賴具體實現,把配置文件的介面對應的數據訪問層實現類替換即可,配置文件格式為InterFace Map 實現類
數據訪問層的封裝公共增刪改查,Unity 管理 EF DBcontext,保持全局或線程單例還沒有看到,最近在學記憶體管理和.Net垃圾回收