記錄對依賴註入的小小理解和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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...