-1

晚上好,我在一个中型项目中第一次尝试用 DI 实现 SOLID 原理。大多数时候我都明白,但现在我遇到了麻烦。让我举一个糟糕的例子,但它显示了应用程序的结构。我继承了具有不同构造函数的类(下面提供的代码)。当我需要一个实例时,我知道我需要的类。因此,关于此代码的 2 个问题:1/在这种情况下我是否必须使用接口来实现 SOLID 原理(或者只是在 Program.cs 中声明 ClassA 的实例,如 ClassA example=new ClassA("text"))2/做得好吗?(什么是好的/什么是坏的,应该做什么/应该避免什么?)

class Program
{
    static void Main(string[] args)
    {
        IFactory exemple = new Factory();
        //With Unity--> exemple=Resolve<IFactory>();
        exemple.GetTextClassA("test");
        exemple.GetTextClassB(1);

        Console.ReadLine();
    }
}

public interface IFactory
{
    ClassA GetTextClassA(string text);
    ClassB GetTextClassB(int text);
}

public class Factory : IFactory
{
    public ClassA GetTextClassA(string text)
    {
        return new ClassA(text);
    }
    public ClassB GetTextClassB(int text)
    {
        return new ClassB(text);
    }
}

public abstract class MainClass
{
    private string _text;

    public MainClass(){}

    protected abstract string GetText();
    protected virtual void Initialize()
    {
        _text = GetText();
        Console.WriteLine(_text);
    }
    public string TextToDisplay
    {
        get { return _text; }
    }
}

public class ClassA : MainClass
{
    string _textA;
    public ClassA(string textParam)
    {
        _textA = textParam;
        base.Initialize();
    }
    protected override string GetText()
    {
        return "Text is :"+_textA;
    }
}

public class ClassB : MainClass
{
    int _numParam;
    public ClassB(int numParam)
    {
        _numParam = numParam;
        base.Initialize();
    }
    protected override string GetText()
    {
        return "Text is :" + _numParam.ToString();
    }
}

非常感谢您的评论。

4

1 回答 1

2

您似乎没有注入任何依赖项。

DI 的最低要求需要两件事:

  1. 依赖关系应该被推送,而不是被拉取。
  2. 依赖关系图应该在一个地方组成,在启动时,在一个称为组成根的地方。

一个非常基本的例子

interface IServiceA
{
    void Foo();
}

interface IServiceB
{
    void Bar();
}

class ServiceA : IServiceA
{
    public void Foo() { do something ; }
}

class ServiceB : IServiceB
{
    public void Bar() { do something else; }
}

interface IProgram
{
    void Execute();
}

class Program : IProgram
{
    private readonly IServiceA _serviceA;
    private readonly IServiceB _serviceB;

    public Program(IServiceA serviceA, IServiceB serviceB)
    {
        _serviceA = serviceA;  //Injected dependency
        _serviceB = serviceB;  //Injected dependency
    }

    public void Execute()
    {
        _serviceA.Foo();
        _serviceB.Bar();
    }
}

void Main()
{
    //Composition root
    var container = new UnityContainer();
    container.RegisterType<IServiceA, ServiceA>();
    container.RegisterType<IServiceB, ServiceB>();
    container.RegisterType<IProgram, Program>();

    //The one and only one entry point for Program
    container.Resolve<IProgram>().Execute();
}

这里发生了什么?

Program是你做所有事情的主要课程。但它也无能为力。在 SRP 下,它将有趣的职责卸载到其他类(ServiceAServiceB)。只有它不知道类是什么——只知道它需要的接口。它不知道它们来自哪里,也不知道它们是如何产生的。它们就在那里,因为它们在Program创建时被推送(注入)。

Unity 容器设置了所有Program需要的接口的注册。它将通过构造函数参数注入依赖Program项(Unity 会自动为您执行此操作)。然后程序可以再次调用服务来完成工作,但不知道它们来自哪里。

我们为什么要这样做?几个原因

  1. 测试程序可以创建实现IServiceAIServiceB. 通过注入这些存根依赖项,测试可以只关注Program.

  2. 通过将特定的接口作为构造函数参数,它所Program依赖的内容立即变得显而易见。如果你得到错误的接口,程序甚至不会编译。这比等待运行时发现您需要的服务不可用要好得多(这就是我们不注入 Unity 容器本身的原因——如果不阅读,您将无法判断哪些接口Program将尝试提取所有代码。与服务定位器模式或简单的静态工厂相同)。

  3. 通过使用容器注入依赖项,您还允许依赖项具有依赖项(例如,如果ServiceA对 具有依赖项ServiceC)。Unity 容器也会注入到注入的类中,k 并注入到注入的注入类中,依此类推。

  4. 您在组合根中管理生命周期(每个请求、每个线程或每个进程),因为这是责任所在。您不希望对象生命周期逻辑分散在整个代码库中,因为这使得在每个用户具有线程的应用程序域与具有不同生命周期规则的服务或 Windows 应用程序中运行相同的对象变得非常困难。

于 2017-10-24T23:39:30.243 回答