【问题标题】:Creating element inside IEnumerable instead of adding existing element to it在 IEnumerable 中创建元素,而不是向其中添加现有元素
【发布时间】:2017-04-27 11:07:58
【问题描述】:

使用这种方法将新项目添加到自定义集合中很好吗?不是添加现有元素,而是在集合中创建新元素?方法名称“Add”是否适合这种情况? (目的是隐藏存储库。)谢谢。

public class MyObject
{
    public int ID { get; }
    public Value1 { get; }
    public Value2 { get; }
}

public interface ICustomCollection : IEnumerable<MyObject>
{
    MyObject Add(value1, value2);
}

public class CustomCollection : ICustomCollection
{
    MyObjectFactory factory;
    MyObjectRepository repository;

    public IEnumerator<MyObject> GetEnumerator()
    {
        return repository.GetAllObjects();
    }

    public MyObject Add(value1, value2)
    {
        var newItem = factory.Create(value1, value2);
        repository.AddObject(newItem);
        return newItem;
    }

    //...
}

【问题讨论】:

  • 我想你需要问问你自己,我需要定制收藏吗?答案几乎总是否定的。您似乎正在使用此集合向数据库添加项目?
  • “答案几乎总是否定的。” -- 您是否有书面证据支持该声明?
  • “书面证据”就像来自权威机构的博客来源?你要找什么证据?如果你不同意让我们讨论。这就是专业人士和新手分享他们见解的讨论......
  • 我没有看到任何使用这种方法的问题。例如,DataRowCollectionsimilar method
  • @Botonomous 是的,它是旨在隐藏 DAL 级别的 DDD 层抽象之一

标签: c# oop design-patterns domain-driven-design ienumerable


【解决方案1】:

我认为您不需要来自IEnumerable&lt;T&gt; 的实施。没有它,引入存储库接口就足够了。

public interface IMyObjectRepostory
{
    IEnumerable<MyObject> GetAll();
    MyObject Add(value1, value2);
}

public class MyObjectRepostory
{
    public IEnumerable<MyObject> GetAll()
    {
        _repository.GetAllObjects();
    }

    MyObject Add(value1, value2)
    {
        var newItem = factory.Create(value1, value2);
        repository.AddObject(newItem);
        return newItem;
    }
}

唯一困扰我的是,您的存储库依赖于工厂。 Repository 是数据库的抽象,数据库的主要职责是读写数据。您不应该在数据库操作中使用一些“业务”逻辑。

但是,如果您删除工厂责任,那么您最终会得到简单的存储库接口

public interface IMyObjectRepostory
{
    IEnumerable<MyObject> GetAll();
    void Add(newMyObject);
}

并使用它

IMyObjectRepository repository = new MyObjectRepository();
var allobjects = repository.GetAllObjects();

var newObject = factory.Create(value1, value2);
repository.Add(newObject);

您可以考虑多一层抽象来封装创建和保存。

public class MyObjectChooseBetterName
{
    private readonly IMyObjectRepository _repository;
    private readonly MyObjectFactory _factory;

    public MyObjectChooseBetterName(IMyObjectRepository repository,
                                    MyObjectFactory factory)
    {
        _repository = repository;
        _factory = factory;
    }

    public MyObject CreateAndSave(object value1, object value2)
    {
        var newObject = _factory.Create(value1, value2);
        _repository.Add(newObject);
        return newObject;
    }
}

并使用它

var manager = new MyObjectChooseBetterName(repository, factory);
var newObject = manager.CreateAndSave(value1, value2);

【讨论】:

  • 这种方法违反了SRP 原则。在 DDD 中,存储库应该有一个方法 'save' 或 'persist' 接受完整的 Aggregate 实例并将其持久化到底层持久性中,并且不应尝试封装 Aggregate 的创建
  • @ConstantinGALBENU - 同意,进一步阅读 - 第一个示例是“重构”的 OP 方法,后来我试图解释为什么这是一种错误的方法
  • @ConstantinGALBENU "在 DDD 中,存储库应该有一个方法 'save' 或 'persist'" - 不同意。您可以为您的存储库提供一个简单集合的形状(事实上,这是原始 DDD 书中推荐的方式)并在工作单元级别处理保存。
  • @guillaume31 是的,add 会是一个更好的名字
【解决方案2】:

您不需要集合来隐藏您的存储库,因为存储库已经充当了外部世界的集合。

对于需要全局访问的每种类型的对象,创建一个可以提供内存幻象的对象 该类型的所有对象的集合

来自 Vernon 的 Implementing DDD,第 401 页,引用 Evans 的 original DDD book 关于存储库。

此外,内聚集合通常不会创建对象。它们处理现有对象(或原始值)。

【讨论】:

    猜你喜欢
    • 2022-01-17
    • 2019-10-17
    • 1970-01-01
    • 1970-01-01
    • 2021-01-31
    • 2018-09-28
    • 2021-03-04
    • 1970-01-01
    • 2016-07-22
    相关资源
    最近更新 更多