记录对依赖注入的小小理解和autofac的简单封装

首先,我不是一个开发者,只是业余学习者。其次我的文化水平很低,写这个主要是记录一下当前对于这块的理解,因为对于一个低水平 的业余学习者来说,忘记是很平常的事,因为接触、应用的少,现在理解,可能过段时间就会忘了,自己记录下来应该可以少走些弯路,以免从头再来查找资料。

另外,如果我的记录能帮忙到一些朋友的话,也难免会有些小满足的。学习的门槛除了理解能力,绝大部分来自于英文水平和专业术语,我希望的是我能用比较通俗易懂的表达,获得大家的理解,更希望大牛们是如是做的,所以写这个更希望的是能得到大牛的帮助。

下面是我对依赖注入在应用场景的理解

从框架设计方面 你希望的是你设计的架构能有不同的技术(或者叫第三方组件)实现,你只需要通过在固定地方修改极少的代码便可以。

来个例子吧,假如现在有两个不同的技术,当然它们应该是在不同的程序集中的,只是为了方便把它们放在一起

    /// <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>();//方便客户端调用时不需要设置属性
            }
        }
    }
}

时间: 2024-10-10 21:47:03

记录对依赖注入的小小理解和autofac的简单封装的相关文章

依赖注入和Guice理解

理解依赖注入,这篇文章写得非常好,结合spring的依赖注入分析的. http://blog.csdn.net/taijianyu/article/details/2338311/ 大体的意思是: 有一个类A,这个类里的属性m(属性是接口类型)需要我们通过构造器或者setter方法传入(比如传入一个B接口实现类的实例,为啥属性或方法的参数类型都是接口类型,因为这样可以传接口不同实现类的实例啊),来为这个类A的该属性m设值.类A有了m属性值,就可以实现很多逻辑了. 在spring框架里,我们不需要

控制反转(IOC) 和依赖注入(DI) 的理解

1.      IOC(控制反转) inverseof control是spring容器的内核,AOP.声明事务等功能在此基础上开花结果. 2.      通过实例理解IOC概念: 实例:<墨攻>电影中有一个场景:当刘德华所饰演的墨者革离到达梁国都城下,城上梁国守军问道:“来者何人?“刘德华回答道:“墨者革离”.以此场景通过一个java类为这个“城门叩问”的场景进行编剧. MoAttract:通过演员安排剧本 public class MoAttack { public voidcityuGa

对spring控制反转以及依赖注入的理解

一.说到依赖注入(控制反转),先要理解什么是依赖. Spring 把相互协作的关系称为依赖关系.假如 A 组件调用了 B 组件的方法,我们可称A 组件依赖于 B 组件. 二.什么是依赖注入. 在传统的程序设计过程中,通常由调用者来创建被调用者的实例. 在依赖注入的模式下,创建被调用者的工作不再由调用者来完成,因此称为控制反转:创建被调用者实例的工作通常由Spring 容器来完成,然后注入给调用者,因此也称为依赖注入. 自己理解:即一句话,由spring容器来控制组件A的调用的具体对象B.组件A依

依赖注入和控制反转的理解,写的太好了。

学习过spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的,今天和大家分享网上的一些技术大牛们对Spring框架的IOC的理解以及谈谈我对Spring Ioc的理解. 一.分享Iteye的开涛对Ioc的精彩讲解 首先要分享的是Iteye的开涛这位技术牛人对Spring框架的IOC的理解,写得非常通俗易懂,以下内容全部来自原文,原文地址:http://jinniansh

那些总是会问到的面试题:Spring依赖注入和控制反转的理解

IoC是什么Ioc-Inversion of Control,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制.如何理解好Ioc呢?理解好Ioc的关键是要明确"谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了",那我们来深入分析一下: 谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象:而

依赖注入和控制反转的理解

学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的,今天和大家分享网上的一些技术大牛们对Spring框架的IOC的理解以及谈谈我对Spring Ioc的理解. 1.1.IoC是什么 Ioc-Inversion of Control,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的

控制反转和依赖注入的理解(通俗易懂)

转自:    https://blog.csdn.net/sinat_21843047/article/details/80297951 https://jinnianshilongnian.iteye.com/blog/1413846 学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的,今天和大家分享网上的一些技术大牛们对Spring框架的IOC的理解以及谈

[javascript] 反射与依赖注入!

对于javascript中的反射的理解,一直都是认为,利用数组对回调函数进行保存,之后在适当的时刻利用call或是apply 方法,对回调进行调用即可,一般如下操作: 首先定义两个方法: var service = function() { return { name: 'Service' }; } var router = function() { return { name: 'Router' }; } 我们有另一个函数需要用到这两个模块. var doSomething = functio

工厂方法模式与IoC/DI控制反转和依赖注入

IoC——Inversion of Control  控制反转 DI——Dependency Injection   依赖注入 要想理解上面两个概念,就必须搞清楚如下的问题: 参与者都有谁? 依赖:谁依赖于谁?为什么需要依赖? 注入:谁注入于谁?到底注入什么? 控制反转:谁控制谁?控制什么?为何叫反转(有反转就应该有正转了)? 依赖注入和控制反转是同一概念吗? 下面就来简要的回答一下上述问题,把这些问题搞明白了,IoC/DI也就明白了.(1)参与者都有谁: 一般有三方参与者,一个是某个对象:一个