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; } } }
無論是構造對象,仍是注入對象,這裏都是靠反射作到的函數
有了依賴注入,纔可能作到無限層級的依賴抽象,才能作到控制反轉ui
IOC Unity容器 能夠經過代碼註冊或配置文件註冊接口對應實現類,實現了不依賴具體,能夠對對象全局單例,線程單例this
例子1spa
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 業務擴展,新加功能code
應該是加幾個接口和實現類的映射,就能夠解決了。對象
例子3 實現AOPblog
方法須要加日誌,加異常管理,能夠不修改原有代碼,直接新加異常管理類等的類庫,在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垃圾回收