記錄對依賴註入的小小理解和autofac的簡單封裝

来源:http://www.cnblogs.com/yuzeyong/archive/2016/04/02/5347717.html
-Advertisement-
Play Games

首先,我不是一個開發者,只是業餘學習者。其次我的文化水平很低,寫這個主要是記錄一下當前對於這塊的理解,因為對於一個低水平 的業餘學習者來說,忘記是很平常的事,因為接觸、應用的少,現在理解,可能過段時間就會忘了,自己記錄下來應該可以少走些彎路,以免從頭再來查找資料。 另外,如果我的記錄能幫忙到一些朋友 ...


      首先,我不是一個開發者,只是業餘學習者。其次我的文化水平很低,寫這個主要是記錄一下當前對於這塊的理解,因為對於一個低水平 的業餘學習者來說,忘記是很平常的事,因為接觸、應用的少,現在理解,可能過段時間就會忘了,自己記錄下來應該可以少走些彎路,以免從頭再來查找資料。

     另外,如果我的記錄能幫忙到一些朋友的話,也難免會有些小滿足的。學習的門檻除了理解能力,絕大部分來自於英文水平和專業術語,我希望的是我能用比較通俗易懂的表達,獲得大家的理解,更希望大牛們是如是做的,所以寫這個更希望的是能得到大牛的幫助。

     下麵是我對依賴註入在應用場景的理解

     從框架設計方面 你希望的是你設計的架構能有不同的技術(或者叫第三方組件)實現,你只需要通過在固定地方修改極少的代碼便可以。

     來個例子吧,假如現在有兩個不同的技術,當然它們應該是在不同的程式集中的,只是為了方便把它們放在一起

    /// <summary>
    /// 第三方組件A
    /// </summary>
    public class ModuleA 
    {
        public void Say()
        {
            Console.WriteLine("it is ModuleA");
        }
    }

    /// <summary>
    /// 第三方組件B
    /// </summary>
    public class ModuleB 
    {
        public void Say()
        {
            Console.WriteLine("it is ModuleB");
        }
    }

 

   你希望你能應用任意其中一個,並且可以隨意更改。你可以對外抽象出一個約束介面或者抽象類,下麵我用的是介面,你可以在你的設計中,通過構造函數來引用

 /// <summary>
    /// 介面
    /// </summary>
    public interface IInterface
    {
        void Say();//介面約束必須實現這個方法
    }
    public class BaseStyle
    {
        private IInterface module;//你並不知道也不關心當前用的是哪個組件,只要組件能實現這個介面就行
        public BaseStyle(IInterface module)//能過構造函數引用介面
        {
            this.module = module;
        }
        public void Say()
        {
            module.Say();
        }
    }

 

  通過屬性引用

    /// <summary>
    /// 通過屬性引用組件方式
    /// </summary>
     public  class BaseStyle
    {
        public IInterface Module { get; set; }
        public void Say()
        {
            Module.Say();
        }
    }

  

 

當你要應用任意一個組件時,只須要讓它實現介面

public class ModuleA : IInterface
    {
        public void Say()
        {
            Console.WriteLine("it is ModuleA");
        }
    }

  

這樣就把BaseStyle類的Say方法分離出來,通過介面的實現類來完成。相當於介面的實現類可以是任意類。這便是傳說中的介面分離,低藕合思想。例子不需要大,理解才是最重要。往大了說,這就相當於是面向介面編程。這是架構設計方面 。

      然後就是應用了,也就是註入工作,Autofac之類的依賴註入組件不是必須的,只是當你的程式大了,用這些封裝好的組件會更方便,易維護。你可以new BaseStyle然後傳入對就的參數或設置屬性就行了。

      我一般用的是Autofac,用autofac,代碼應該 是這樣的

class Program
    {
        static void Main(string[] args)
        {
            ContainerBuilder builder = new ContainerBuilder();

            builder.Register(o => new BaseStyle(o.Resolve<IInterface>()));//實例註入

            builder.RegisterType<ModuleA>().As<IInterface>();             //類型註入

            using (var container = builder.Build())

            {
                BaseStyle bs = container.Resolve<BaseStyle>();
                bs.Say();
            }

            Console.ReadKey();
        }

  當然這樣用肯定是沒必要用autofac的,當有很多類須要用到Autofac註入時,這樣並不會減少代碼量,當要修改時,每個地方都要修改,如果只對Autofac停留在這個層面,還是不必要用它的好。

     我比較喜歡的是封裝一個Container類,由於我一慣喜歡用強類型,所以沒有試過通過配置文件來配置。可能是因為我沒有接觸到真實項目的原因吧

封裝一個類

 public class ServiceContainer
    {
        private ServiceContainer() { }//不對外提供構造函數

        private static IContainer container;

        /// <summary>
        /// 初始化container
        /// </summary>
        /// <param name="action"></param>
        public static void Initialize(Action<ContainerBuilder> action)
        {
            if(action!=null)
            {
                ContainerBuilder builder = new ContainerBuilder();
                action(builder);
                container = builder.Build();
            }
        }

        /// <summary>
        /// 封裝一個不帶參數的IContainer的方法
        /// </summary>
        /// <typeparam name="Tservice"></typeparam>
        /// <returns>返回一個註入的服務類實例</returns>
        public static Tservice Resolve<Tservice>()
        {
            ThrowIfNotInitialized();             //檢測容器是否初始化
            return container.Resolve<Tservice>();
        }

        //此處省略其它IContainer方法的封裝

        /// <summary>
        /// 檢測容器是否初始化
        /// </summary>
        private static void ThrowIfNotInitialized()
        {
            if (container == null)
                throw new InvalidOperationException("請先初始化容器,調用Initialize()方法");
        }
    }

   通過個類提供的靜態初始化方法,可以在應用程式開始處,將所有要註入的依賴註入到容器中,然後你可以在程式的任意地方通過靜態方法Resolve<T>方法從容器中取得你想要的具體依賴。這裡我只封裝了一個方法,還可以封裝更多的靜態方法,靈活調用。

     最後再傳上測試的所有代碼。這裡我抽象出了一些基類,設置好依賴註入,方便客戶端調用時不需要傳入參數或是設置屬性,個人感覺應該比較完美了

using System;
using Autofac;

namespace AutofacDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceContainer.Initialize(o =>
            {
                o.RegisterType<ModuleA>().As<IInterface>();
                //o.RegisterType<ModuleB>().As<IInterface>();需要用其它實現時,只須要修改傳入對應的類型
            });

            StyleA a = new StyleA();//純凈的客戶端調用
            StyleB b = new StyleB();
            a.Say();
            b.Say();

            #region 基本註入
            //ServiceContainer.Initialize(o =>
            // {
            //     o.RegisterType<ModuleA>().As<IInterface>();
            // });


            //StyleA a = new StyleA(ServiceContainer.Resolve<IInterface>());
            //StyleB b = new StyleB();
            //b.Module = ServiceContainer.Resolve<IInterface>();
            //a.Say();
            //b.Say();
            #endregion

            #region 實例註入、屬性註入
            //ServiceContainer.Initialize(o =>
            //{
            //    o.Register(c => new StyleA(c.Resolve<IInterface>()));             //實例註入
            //    o.Register(c => new StyleB { Module = c.Resolve<IInterface>() });//屬性註入
            //    o.RegisterType<ModuleA>().As<IInterface>();
            //});
            //StyleA a = ServiceContainer.Resolve<StyleA>();
            //StyleB b = ServiceContainer.Resolve<StyleB>();

            //a.Say(); b.Say(); 
            #endregion

            Console.ReadKey();
        }
    }

    /// <summary>
    /// 介面
    /// </summary>
    public interface IInterface
    {
        void Say();
    }

    /// <summary>
    /// 介面的某個實現類A,通常相當於第三方組件
    /// </summary>
    public class ModuleA : IInterface
    {
        public void Say()
        {
            Console.WriteLine("it is ModuleA");
        }
    }

    /// <summary>
    /// 介面的某個實現類B,通常相當於第三方組件
    /// </summary>
    public  class ModuleB : IInterface
    {
        public void Say()
        {
            Console.WriteLine("it is ModuleB");
        }
    }

    public class BaseStyle
    {
        private IInterface module;
        public BaseStyle(IInterface module)
        {
            this.module = module;
        }
        public void Say()
        {
            module.Say();
        }
    }

    /// <summary>
    /// 基類通過構造函數引用組件方式
    /// </summary>
    public abstract  class BaseStyleA
    {
        private IInterface module;
        protected BaseStyleA(IInterface module)
        {
            this.module = module;
        }
        public void Say()
        {
            module.Say();
        }
    }

    /// <summary>
    /// 基類通過屬性引用組件方式
    /// </summary>
    public abstract class BaseStyleB
    {
        public virtual IInterface Module { get; set; }
        public void Say()
        {
            Module.Say();
        }
    }

    public class StyleA:BaseStyleA
    {
        public StyleA(IInterface module) : base(module) { }
        public StyleA() : base(ServiceContainer.Resolve<IInterface>())//方便客戶端調用時不需要傳參
        {

        }
    }
    public class StyleB:BaseStyleB
    {
        public override IInterface Module
        {
            get
            {
                return ServiceContainer.Resolve<IInterface>();//方便客戶端調用時不需要設置屬性
            }
        }
    }
}
View Code

 

 

 

 

    


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • spring.jar 是包含有完整發佈模塊的單個jar 包。但是不包括mock.jar, aspects.jar, spring-portlet.jar, and spring-hibernate2.jar。spring-src.zip就是所有的源代碼壓縮包。除了spring.jar 文件,Spri ...
  • 這個對象池相當小巧,支持加鎖以方便支持線程安全,當然了,如果在單線程中使用,可以指定一個偽鎖。 這個對象池並不能解決記憶體碎片問題,只是用空間換時間。這個代碼相當簡短,一看就明白,所以不寫用例了。還有這個鎖的代碼就不貼了,因為鎖的樣式各有不同,還有避免跑題,避免喧賓奪主。 上代碼: 不夠150字不允許 ...
  • JAVA Quick Java 8 or Java 7 Dev Environments With Docker Printing arrays by hacking the JVM Mobile How to Create a News Reader With React Native: Web ... ...
  • 數量 時間限制:200 ms | 記憶體限制:65535 KB 難度:0 HJS大牛想去街上吃飯,街道旁邊拴著很多狗,他想我堂堂......(省略n個字)豈會被狗咬,所以他很牛的從狗的面前經過,不管是否被上一條狗咬過,下次還會從狗的面前過(J I A N) 現在問題來了,我們給狗編號從1...n,有多 ...
  • 這個星期接到一個新的任務:解決HQ(一個用JAVA開發的開源的運維監控平臺)現在遇到的snmp升級到3.0後bug。公司用的HQ是4.6版本。於是,我把項目從gitlab上clone下來後,就開始了我的填坑之旅。坑了幾天坑,到目前,正常情況,應該只有最後一個坑了,應該是關於tomcat運行環境的。閑 ...
  • 安裝python3.5可能使用的依賴 到python官網找到下載路徑, 用wget下載 解壓tgz包 把python移到/usr/local下麵 刪除舊版本的python依賴 進入python目錄 配置 編譯 make 編譯,安裝 刪除舊的軟鏈接,創建新的軟鏈接到最新的python Enjoy yo ...
  • 頭文件 my_sql.h 實現文件 my_sql.cpp 調用實例 main.cpp ...
  • Atitit.eclipse git使用 1. Git vs svn1 1.1. 直接記錄快照,而非差異比較1 1.2. Git的patch則不依附於branch,commit和commit之間的關係是一個GRAPH3 1.3. hg 本地有更改的時候,可以直接 pull 遠程代碼,然後在自己當前更 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...