避免在域模型中使用循环引用

时间:2009-05-28 10:17:08

标签: c# .net design-patterns domain-driven-design

这一定是一种常见的情况,已经有很多关于它的文章,希望甚至是一个非常好的模式。我有一个域模型,其中自定义容器包含实体。例如(为简洁而排除的属性和接口):

class Entity
{
    public int Id;
    public EntityContainer ParentContainer;
}


class EntityContainer
{
    public int Id;
    public IList<Entity> Entities = new List<Entity>();

    public void AddEntity(Entity entity)
    {
        entity.ParentContainer = this;
        Entities.Add(entity);
    }
}


class Main
{
    public Main()
    {
        Entity entity1 = new Entity();
        Entity entity2 = new Entity();
        EntityContainer entityContainer = new EntityContainer();
        entityContainer.AddEntity(entity1);
        entityContainer.AddEntity(entity2);

        // Can now traverse graph easily, e.g.
        Console.WriteLine("entity1's parent container ID = " + entity1.ParentContainer.Id);
        Console.WriteLine("Container contains at least this entity ID: " + entityContainer.Entities[0].Id);

    }
}

我现在可以通过两种方式轻松遍历我的对象图,但创建了一个循环引用。你会创建第三种类型来离婚依赖吗?

提前致谢

4 个答案:

答案 0 :(得分:4)

循环引用本身没有任何问题,它们在.NET Framework中被广泛使用,例如: XmlNode.OwnerDocument,Control.Parent。

如果你需要遍历树,那么可以使用后向引用。

在COM中,循环引用很棘手,因为如果您将容器及其所有子项设置为空,那么对象将无法正确清理,因为子项仍保留对父项的引用。但是,.NET垃圾收集对它的实现方式没有任何问题。

答案 1 :(得分:2)

容器是否需要了解内容的类型?如果没有,泛型可以避免这种情况 - 即Container<T>发生以使用Container<Entity>。除此之外;将必要的细节推送到可以引用的程序集中的接口(或基类)是一种常见的方法。

就个人而言,我会尽量避免让孩子了解父母。

也;请注意,如果您执行,请关闭抽象(界面等)路线;如果您正在使用(例如)xml序列化,这可能会产生很大的影响。


(编辑评论) 好;第一:引起循环引用(在程序集内)的问题是什么;如果没有,请不要管它。如果有问题,那么你需要一个额外的类型;可能是一些表示具体类型的接口 - 即Entity : IEntityEntityContainer仅知道IEntity(或IEntityContainer或两者兼有),

答案 2 :(得分:1)

因为我没有看到你的班级模型有问题,但你可以很容易地做一个干净的切割。使实体实现一个接口IEntity并使EntityContainer保持一个IList,除非你有一个非常具体的理由使用IList,你应该考虑IEnumerable,这将使你使用的EntityClass的使用者容易。传递任何IEntity数组,或选择IEntities的linq表达式是可能的

答案 3 :(得分:1)

在我的书中使用循环引用的对象是正确的,只要你在设计这些对象时使用某种延迟加载模式。

e.g。

您想要访问: Company.Employee 在另一种情况下: Employee.Company

这是一个循环引用,即 Company.Employee.Company.Employee 等。

如果这些属性不是延迟加载的,例如公司对象始终加载其Employee属性,而Employee对象始终加载其Company属性,然后在引入数据源时它将无法正常工作。