接口和继承的类

时间:2017-10-24 23:11:50

标签: c# interface inherited

晚上好, 我正试图在中型项目中首次使用DI实现SOLID原理。 大部分时间我都明白,但现在我遇到了麻烦。 让我举一个可怜的例子,但它显示了应用程序的结构。 我继承了具有不同构造函数的类(下面提供的代码)。当我需要一个实例时,我知道我需要的课程。 那么,关于这段代码的2个问题: 1 /在这种情况下我是否必须使用接口来实现SOLID原理(或者在Program.cs中简单地声明ClassA的实例,如ClassA exemple = 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();
    }
}

非常感谢您的评论。

1 个答案:

答案 0 :(得分:2)

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

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

  1. 应该推动依赖性,而不是拉动。
  2. 依赖图应该在启动时在一个地方由composition root组成。
  3. 一个非常基本的例子

    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将会是什么尝试拉而不读取所有代码。与Service Locator pattern或简单的静态工厂相同。

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

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