依赖反转原理,IoC容器和依赖注入:第1部分

目录

介绍

先决条件

依赖倒置原则(DIP)

总结


介绍

在处理WPF应用程序时,我遇到过诸如Unity容器,IoC,依赖注入之类的术语。当时,我很迷茫,想着这一切的需要。但后来,当我逐渐了解到它的好处时,我意识到它的实际需要。

在本文中,我将尝试解释DIIoC的需求和用法。基本上,本文分为五个部分:

  • 第1部分:依赖反转原理(当前正在阅读)
  • 第2部分:控制反转和IoC容器
  • 第3部分:自定义IoC容器
  • 第4部分:具有生命周期选项的自定义IoC容器
  • 第5部分:使用Microsoft Unity的依赖项注入(DI)

本文的这一部分是关于依赖倒置原理的。希望您会发现本文易于理解和实现。

先决条件

最好对以下项一无所知:

  • 开闭原则
  • 接口隔离原理

依赖倒置原则(DIP

DIPSOLID原则之一,由Robert Martin C.先生在1992年提出。

根据罗伯特·马丁(C. Robert Martin)的依赖倒置原则:

  1. 高级模块不应依赖于低级模块。两者都应依赖抽象。
  2. 抽象不应依赖细节。细节应依赖于抽象。

DIP是指将常规依赖性从高级模块转换为低级模块。

Bob Martin Peper期刊的示例:

在图1中,一个复制程序(高级模块)从键盘读取并写入打印机。这里的复制程序取决于Read KeyboardWrite Printer并紧密耦合

public class Copy
{
    public void DoWork()
    {
        ReadKeyboard reader = new ReadKeyboard();
        WritePrinter writer = new WritePrinter();

        string data = reader.ReadFromKeyboard();
        writer.WriteToPrinter(data);
    }
}

在我们要求向程序中添加更多读取器或写入器之前,此实现似乎非常好。在这种情况下,我们需要更改复制程序以适应新的读者和作家,并且需要编写条件语句,该条件语句将根据用途选择读者和作家,这违反了面向对象设计的打开/关闭原理。

例如,我们要扩展复印程序(参见图1.b),该程序也可以从扫描仪读取并写入闪存盘。在这种情况下,我们需要修改复制程序:

public class Copy
{
    public void DoWork()
    {
        string data;
        switch (readerType)
        {
            case  "keyboard":
                ReadKeyboard reader = new ReadKeyboard();
                data = reader.ReadFromKeyboard();
                break;
            case "scanner":
                ReadScanner reader2 = new ReadScanner();
                data = reader2.ReadFromScanner();
                break;
        }
        switch (writerType)
        {
            case "printer":
                WritePrinter writer = new WritePrinter();
                writer.WriteToPrinter(data);
                break;
            case "flashdisk":
                WriteFlashDisk writer2 = new WriteFlashDisk();
                writer2.WriteToFlashDisk(data);
                break;
        }
    }
}

同样,如果您继续添加更多读取器或写入器,则我们需要更改复制程序的实现,因为复制程序取决于读取器和写入器的实现。

为了解决这个问题,我们可以修改copy程序,使其依赖于抽象而不是依赖于实现。下图说明了反转依赖关系。

在上图中,Copy程序依赖于两个抽象,IReaderIWriter执行。只要底层组件能够对抽象进行确认,copy程序就可以从这些组件中读取内容。

例如,在上图中,ReadKeyboard实现IReader接口和WritePrinter实现IWriter,因此使用IReaderIWriter接口复制程序可以执行复制操作。因此,如果我们需要添加更多低级组件(如扫描仪和闪存盘),则可以通过从扫描仪和闪存盘来实现。以下代码说明了这种情况:

public interface IReader
{
    string Read();
}

public interface IWriter
{
    void Write(string data);
}

public class ReadKeyboard : IReader
{
    public string Read()
    {
        // code to read from keyboard and return as string
    }
}

public class ReadScanner : IReader
{
    public string Read()
    {
        // code to read from scanner and return as string
    }
}

public class WritePrinter : IWriter
{
    public void Write(string data)
    {
        // code to write to the printer
    }
}

public class WriteFlashDisk : IWriter
{
    public void Write(string data)
    {
        // code to write to the flash disk
    }
}

public class Copy
{
    private string _readerType;
    private string _writerType;

    public Copy(string readerType, string writerType)
    {
        _readerType = readerType;
        _writerType = writerType;
    }

    public void DoWork()
    {
        IReader reader;
        IWriter writer;
        string data;
        switch (readerType)
        {
            case  "keyboard":
                reader = new ReadKeyboard();
                break;
            case "scanner":
                reader = new ReadScanner();
                break;
        }

        switch (writerType)
        {
            case "printer":
                writer = new WritePrinter();
                break;
            case "flashdisk":
                writer = new WriteFlashDisk();
                break;
        }

        data = reader.Read();
        writer.Write(data);
    }
}

在这种情况下,细节依赖于抽象,但高级类仍依赖于低级模块。在实例化高级模块范围内的低级模块对象时,高级模块仍然需要在添加新的低级组件时进行修改,这不能完全满足DIP

为了删除依赖关系,我们需要在高级模块之外创建依赖关系对象(低级组件),并且应该有某种机制将该依赖关系对象传递给依赖模块。

现在出现了一个新问题,即如何实现依赖倒置。

上述问题的答案之一可以是控制反转(IoC)。考虑以下代码段:

public class Copy
{
    public void DoWork()
    {
        IReader reader = serviceLocator.GetReader();
        IWriter writer = serviceLocator.GetWriter();
        string data = reader.Read();
        writer.Write(data);
    }
}

高亮显示的代码替换了实例化读取器和写入器对象的逻辑。在这里,我们将控件创建从Copy程序(高级模块)转换为服务定位器。因此,copy无需通过添加/删除低级模块来更改程序。

依赖注入是实现IoC的机制之一。在本文的下一部分中,我将介绍什么是控制反转(IoC),以及使用不同机制(依赖注入(DI)是实现之一)实现依赖反转原理的方法。

总结

在本文的这一部分中,我已经解释了依赖性反转原理(DIP)及其在实时场景中的需求。

在本文的后面,我将解释控制反转(IoC)和依赖注入(DI)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章