首页 > 其他分享 >IOC容器和依赖倒置

IOC容器和依赖倒置

时间:2024-08-16 17:05:50浏览次数:10  
标签:容器 IHeadphone 对象 依赖 倒置 IOC public 构造函数

1 依赖倒置

依赖倒置的核心价值:
如果没有依赖倒置,全部都是依赖细节,如果分层架构是 A层---B层--C层---D层---E层---F层,下层的修改,可能会导致上层随之改变,F层如果改变,E层要改,D层要改,C层要改......影响很大,成水波式向上影响,架构就的极度不稳定。
如果都是依赖于抽象的,抽象即接口或抽象类。 抽象是相对稳定的,修改下层不会影响上层。因为上层不是依赖于具体的,这让我们的代码更加稳定。
IOC 控制对象的创建,不就是完全控制了对象的创建吗?所以,IOC的本质是工厂。
既然IOC是工厂,那么工厂生产产品就是创建对象。

2 简单工厂创建对象会不会有什么问题呢?

工厂创建对象,如果对象没有无参数构造函数,必须得按照构造函数参数的要求,准备好构造函数。那就会出现问题:如果对象存在层层依赖,有多少层依赖,就得准备多少个方法。
要解决这个问题,我们就有了这样的一个目标:如果有依赖的,能够做到,在创建对象的时候,能够自动把对象依赖的对象给创建出来,然后传递进去,这样就很好。
Asp.Net Core的内置IOC容器可以帮助我们解决掉这个问题。

3 内置IOC容器

需要引入Microsoft.Extensions.DependencyInjection包。
Zlt.IOC.Interfaces 命名空间下创建接口:

public interface IHeadphone
{
}
public interface IMicrophone
{
}   
public interface IPower
{
}
public interface IPhone
{
    void Call();
    void Init123456678890(IPower iPower);
    IMicrophone Microphone { get; set; }
    IHeadphone Headphone { get; set; }
    IPower Power { get; set; }
}

Zhaoxi.IOC.Services 实现接口:

    public class Headphone : IHeadphone
    { 
        public Headphone()
        {
            Console.WriteLine($"{this.GetType().Name}被构造。。");
        } 
    }
    public class Headphone : IHeadphone
    {
        public Headphone()
        {
            Console.WriteLine($"{GetType().Name}被构造。。");
        }
    }
    public class Microphone : IMicrophone
    {
        public IHeadphone _IHeadphone { get; set; }

        public IHeadphone _IHeadphoneField;

        public void SetHeadphone(IHeadphone headphone)
        {
            _IHeadphoneField = headphone;
        }

        /// <summary>
        /// 没有无参数构造函数
        /// </summary>
        /// <param name="headphone"></param>
        [SelectCtor]
        public Microphone(IHeadphone headphone)
        {
            Console.WriteLine($"{GetType().Name}被构造。。");
        }

        public Microphone(IHeadphone headphone, IHeadphone headphone1)
        {
            Console.WriteLine($"{GetType().Name}被构造。。");
        }
    }
    public class Power : IPower
    {
        public Power(IMicrophone microphone)
        {
            Console.WriteLine($"{GetType().Name}被构造。。");
        }
    }
    public class AndroidPhone : IPhone
    {
        public IMicrophone Microphone { get; set; }
        public IHeadphone Headphone { get; set; }
        public IPower Power { get; set; }

        public AndroidPhone(IPower Power)
        {
            Power = Power;
            Console.WriteLine("{0}构造函数", GetType().Name);
        }

        public void Call()
        {
            Console.WriteLine("{0}打电话", GetType().Name); ;
        }

        public void Init123456678890(IPower iPower)
        {
            Power = iPower;
        }
    }

调用:

//1.IOC容器的实例
ServiceCollection services = new();
//2.注册抽象和具体之间的关系
services.AddTransient<IHeadphone, Headphone>();
services.AddTransient<IMicrophone, Microphone>();
services.AddTransient<IPower, Power>();
services.AddTransient<IPhone, AndroidPhone>();
//3.Buidl下得到一个Provider
ServiceProvider serviceProvider = services.BuildServiceProvider();
//4.创建对象
IHeadphone headphone = serviceProvider.GetService<IHeadphone>();
IMicrophone microphone = serviceProvider.GetService<IMicrophone>();
IPower power = serviceProvider.GetService<IPower>();
IPhone iphone = serviceProvider.GetService<IPhone>();

这就是框架的依赖注入,如果对象A依赖于对象B,对象B依赖于对象C,在创建对象A时,自动先创建对象C,满足对象B的依赖,再创建对象B,满足A的依赖,最后创建出对象A。

4 依赖注入DI

内置容器中,仅支持构造函数注入这一种。依赖注入有3中。

  1. 构造函数注入:如果对象A在构造函数中依赖于对象B,对象B在构造函数中依赖于对象C,如果要构造对象A,自动构造C,传入对象B的构造函数,构造出对象B,传入对象A,构造出对象A;
  2. 属性注入:如果对象A在属性中依赖于对象B,对象B在属性中依赖于对象C,如果要构造对象A,在构造出对象A之后,检测属性,如果属性有依赖,就自动的去创建依赖的对象,创建出来以后,赋值给对象A中共的属性; 如果在创建的过程中,还有依赖,就继续创建
  3. 方法注入:如果对象A在某个方法中依赖于对象B,对象B在某个方法中依赖于对象C,如果要构造对象A,在构造出对象A之后,检测某个方法,如果某个方法的参数有依赖,就自动的去创建某个方法参数依赖的对象,创建出来以后,去执行这个方法,把构造出来的对象传递给这方法的参数; 如果在创建的过程中,还有方法依赖,就继续创建。

5 这个 IOC 和依赖注入 DI 之间,是什么关系?

IOC 是架构设计的一种方案,一种目标;
DI 是实现 IOC 容器的的时候,一种解决依赖问题的技术手段;

6 底层究竟如何实现?

下面就是关于IOC底层的构造函数注入的核心逻辑。
Zlt.IOC.Common 提供公共方法:

public interface IMyServiceCollection
{
    /// <summary>
    /// 注册具体和抽象之间的关系
    /// </summary>
    /// <typeparam name="T">抽象</typeparam>
    /// <typeparam name="S">具体</typeparam>
    public void Register<T, S>() where S : T;
    /// <summary>
    /// 获取对象的实例
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public T GetService<T>();
}
public class MyServiceCollection : IMyServiceCollection
{
    private static Dictionary<string, Type> MapDic = new Dictionary<string, Type>();
    /// <summary>
    ///  保存  注册具体和抽象之间的关系
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="S"></typeparam>
    public void Register<T, S>() where S : T
    {
        MapDic.Add(typeof(T).FullName, typeof(S));
    }
    /// <summary>
    ///  获取对象的实例
    /// </summary>
    /// <typeparam name="T">参数:必然是抽象</typeparam>
    /// <returns></returns>
    public T GetService<T>()
    {
        string abstractFullName = typeof(T).FullName;
        Type type = MapDic[abstractFullName];
        return (T)CreateInstance(type);
    }
    /// <summary>
    /// 创建对象 有依赖的递归创建
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    public object CreateInstance(Type type)
    {
        ConstructorInfo? ctor = type.GetConstructors()
            .Where(a => a.IsDefined(typeof(SelectCtorAttribute)))
            .FirstOrDefault();
        if (ctor == null)
        {
            ctor = type.GetConstructors()
                .OrderByDescending(c => c.GetParameters().Length)
                .First();
        }
        List<object> parametList = new();
        foreach (var ctorParameter in ctor.GetParameters())
        {
            Type tageType = MapDic[ctorParameter.ParameterType.FullName];
            object oPrarmeter = CreateInstance(tageType);
            parametList.Add(oPrarmeter);
        }
        return Activator.CreateInstance(type, parametList.ToArray());
    }
}
[AttributeUsage(AttributeTargets.Constructor)]
public class SelectCtorAttribute : Attribute
{
}

调用:

IMyServiceCollection myServices = new MyServiceCollection();
myServices.Register<IHeadphone, Headphone>();
myServices.Register<IMicrophone, Microphone>();
myServices.Register<IPower, Power>();
myServices.Register<IPhone, AndroidPhone>();

IHeadphone headphone1 = myServices.GetService<IHeadphone>();
IMicrophone microphone1 = myServices.GetService<IMicrophone>();
IPower power1 = myServices.GetService<IPower>();
IPhone iphone1 = myServices.GetService<IPhone>();

标签:容器,IHeadphone,对象,依赖,倒置,IOC,public,构造函数
From: https://www.cnblogs.com/nullcodeworld/p/18363242

相关文章

  • 11. 盛最多水的容器【 力扣(LeetCode) 】
    一、题目描述给定一个长度为n的整数数组height。有n条垂线,第i条线的两个端点是(i,0)和(i,height[i])。找出其中的两条线,使得它们与x轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。说明:你不能倾斜容器。二、测试用例示例1:输入:[1,......
  • 【容器安全系列Ⅰ】- 以进程视角探索容器
        使用容器的一个很大好处是,大多数时候你不必考虑后台发生了什么,像Docker和Kubernetes这样的工具,在向用户隐藏系统复杂性方面做得很好。    但是,当您需要调试和保护容器环境时,了解如何在底层与容器进行交互会非常有帮助。幸运的是,由于大多数容器化工具......
  • 在K8S中,同⼀个Pod内不同容器哪些资源是共用的,哪些资源是隔离的?
    在Kubernetes(K8S)中,同一个Pod内的不同容器在资源共享和隔离方面有着特定的规则。以下是对这些规则的详细解释:1.资源共享网络命名空间:Pod内的所有容器共享同一个网络命名空间。这意味着它们可以看到相同的网络设备和IP地址,并能够通过localhost相互通信,而无需进行网络地址转换......
  • 容器引擎说明——Contianerd与Docker的区别以及Containerd换源操作
    容器引擎是Kubernetes最重要的组件之一,负责管理镜像和容器的生命周期。Kubelet通过ContainerRuntimeInterface(CRI)与容器引擎交互,以管理镜像和容器。表1容器引擎对比Containerd和Docker组件常用命令对比表2镜像相关功能表3容器相关功能表4Pod相关功能说明:Cont......
  • 手动实现 Spring 底层机制【初始化 IOC容器+依赖注入+BeanPostProcessor 机制+AOP】【
    手动实现Spring底层机制【初始化IOC容器+依赖注入+BeanPostProcessor机制+AOP】【任务阶段4】任务阶段1、2、3链接一、实现任务阶段1-编写自己Spring容器,实现扫描包,得到bean的class对象二、实现任务阶段2-扫描将bean信息封装到BeanDefinition对象,并......
  • k8s集群中pod的容器资源限制和三种探针
    目录1.pod容器的资源限制1.1资源单位2.k8s的健康检查2.1探针的三种规则3.pod容器的启动、退出动作1.pod容器的资源限制当定义Pod时可以选择性地为每个容器设定所需要的资源数量。最常见的可设定资源是CPU和内存大小,以及其他类型的资源。当为Pod中的容器指定......
  • 什么是依赖倒置原则
    依赖倒置原则(DependencyInversionPrinciple,DIP)是面向对象设计原则之一,它是SOLID原则中的"D"。依赖倒置原则的核心思想是高层策略性业务规则不应该依赖于低层的具体实现细节,而两者都应该依赖于抽象。依赖倒置原则主要包含两个基本点:抽象不应该依赖于细节:系统中的抽象层(高层......
  • 介绍Docker容器
    容器是Docker又一核心概念。简单的说,容器是独立运行的一个或一组应用,以及它们的运行态环境。对应的,虚拟机可以理解为模拟运行的一整套操作系统(提供了运行态环境和其他系统环境)和跑在上面的应用。进入Docker容器在使用-d参数时,容器启动后会进入后台。某些时候需要进......
  • flannel容器启动失败,日志报错“Failed to find any valid interface to use: failed t
    现状k8s部署,flannel容器起不来,不断重启,查看日志报错"Failedtofindanyvalidinterfacetouse:failedtogetdefaultinterface:Unabletofinddefaultroute"排查过程根据报错提示,可能是网卡名称奇怪导致,或者没有默认路由查看默认路由很显然是有默认路由的查......
  • 三层架构与解耦——IoC&DI机制【后端 7】
    三层架构与解耦——IoC&DI机制在软件开发领域,三层架构(Controller、Service、Dao)是一种广泛采用的架构模式,它通过将应用程序分为三个主要层次来组织代码,旨在提高代码的可维护性、复用性和可扩展性。而解耦(Decoupling)则是实现这些目标的关键技术之一。本文将深入探讨三层架......