【问题标题】:architecture with Dependency Inversion (prior to a DI Framework)具有依赖反转的架构(在 DI 框架之前)
【发布时间】:2020-03-30 23:51:38
【问题描述】:

我正在学习 D.I. 我的架构有一些问题,也许我遗漏了一些要点。

假设我有这个非 DI 代码(我从文件中读取了“Person”列表)

static void Main()
{
   PersonReaderFromFile personReader = new PersonReaderFromFile("path-to-file");
   Person p = personReader.GetNext();  //return a Person parsed from file line or NULL at EOF
}

class Person 
{
    //stuffs here
}

class PersonReaderFromFile
{
    public Person GetNext()
    {
        Person person = new Person();
        //some logic
        return person;
    }
}

首先,为了实现 D.I.模式,我需要接口,所以我需要

static void Main()
{
   iPersonReader personReader = new PersonReaderFromFile("path-to-file");
   iPerson p = personReader.GetNext();
}

interface iPerson
{
}

class Person : iPerson
{
}

interface iPersonReader
{
    iPerson GetNext();
}

class PersonReaderFromFile : iPersonReader
{
    public iPerson GetNext()
    {
        Person person = new Person();
        //some logic
        return person;
    }
}

现在我的问题是:PersonReaderFromFile 取决于 Person 实现。 没关系? 或者我需要一个额外的类,比如 PersonFactory?

static void Main()
{
    iPersonFactory factory = new PersonFactory();
    iPersonReader personReader = new PersonReaderFromFile("path-to-file", factory);
    iPerson person = personReader.GetNext();
}

interface iPerson
{
}

class Person : iPerson
{
}

interface iPersonReader
{
    iPerson GetNext();
}

class PersonReaderFromFile : iPersonReader
{
    iPersonFactory _factory;

    public PersonReaderFromFile(iPersonFactory factory)
    {
        _factory = factory;
    }

    public iPerson GetNext()
    {
        Person person = _factory.CreateNewPerson();
        //some logic
        return person;
    }
}

interface iPersonFactory 
{
    iPerson CreateNewPerson();
}

class PersonFactory : iPersonFactory
{
    iPerson CreateNewPerson()
    {
        Person person = new Person();
        return person;
    }
}

现在 PersonFactory 依赖于 Person 实现,但它应该是正确的。 有什么建议吗? Tnx 给所有人。

编辑: 我展示了一个示例 PersonReaderFromFile 实现

class PersonReaderFromFile
{
    StreamReader _fileReader;

    public PersonReaderFromFile(string path)
    {
        _fileReader = new StreamReader(file);
    }

    public Person GetNext()
    {
        string line = _fileReader.ReadLine();
        if (line == null)
        {
                _fileReader.Close();
                return null;
        }

       string name, lastName, email;
       ParseInformationFromLine(line, out name, out lastName, out email);

       Person p = new Person { Name = name, LastName = lastName, Email = email };

       return p;
    }

   private ParseInformationFromLine(string line, out string name, out string lastName, out string email)
   {
        //I don't think that matters
   }
}

【问题讨论】:

    标签: c# dependency-injection architecture dependency-inversion


    【解决方案1】:

    PersonReaderFromFile 不依赖于Person。该类似乎只是一个代表运行时数据的 POCO。

    PersonReaderFromFile 依赖于 StreamReader 以及 ParseInformationFromLine 函数

    首先将这些实现细节抽象为他们自己的关注点。

    public interface IReadLines {
        string ReadLine();
    }
    
    public interface IParsePersonInformationFromLine {
        void ParseInformationFromLine(string line, out string name, out string lastName, out string email);
    }
    

    目标类将显式依赖于抽象

    public class PersonReaderFromFile {
        private readonly IReadLines reader;
        private readonly IParsePersonInformationFromLine parser;
    
        public PersonReaderFromFile(IReadLines reader, IParsePersonInformationFromLine parser) {
            this.reader = reader;
            this.parser = parser;
        }
    
        public Person GetNext() {
            string line = reader.ReadLine();
            if (line == null) {
                return null;
            }
    
            string name, lastName, email;
            parser.ParseInformationFromLine(line, out name, out lastName, out email);
    
            Person p = new Person { Name = name, LastName = lastName, Email = email };
    
            return p;
        }
    }
    

    各个抽象将有自己的实现,以满足在运行时使用的所需功能。例如,阅读器在内部仍会使用StreamReader 来获取行。 PersonReaderFromFile 不需要知道有关如何检索行的任何信息。只是它在调用时需要一条线。

    Main 现在可以重构为使用纯 DI,例如

    static void Main() {
        IReadLines reader = new ReadLinesImplementation("path-to-file");
        IParsePersonInformationFromLine parser = new ParsePersonInformationFromLine(); 
        PersonReaderFromFile personReader = new PersonReaderFromFile(reader, parser);
        Person p = personReader.GetNext();  //return a Person parsed from file line or NULL at EOF
    }
    

    还有更多可以应用的重构,但这只是一个简化示例,用于识别应从与实现关注点紧密耦合的代码中抽象出来的实现细节。

    【讨论】:

    • 太棒了!非常感谢您的宝贵时间!如果您愿意,您能否也向我展示您正在谈论的其他重构? (如果你有时间,我不想打扰)
    猜你喜欢
    • 2014-01-22
    • 2012-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-08
    • 2020-11-02
    • 2021-02-19
    相关资源
    最近更新 更多