.net 对于需要引用其他类的类,C#中什么是好的设计模式?

bsxbgnwa  于 9个月前  发布在  .NET
关注(0)|答案(6)|浏览(83)

我正在用C#. NET解决一个商业问题。我有两个类,分别命名为C和W,它们将在不同的时间被独立地示例化。
C类的对象需要包含对0的引用。n个W类对象,即一个C对象最多可以包含n个W对象。
每个W对象需要包含一个C类对象的引用,即一个W对象包含在一个C对象中。
C类的对象通常首先被示例化。在稍后的点,其W内容被发现并被示例化。在后面的这一点上,我需要交叉引用C和W对象。
什么是好的设计模式?实际上,我遇到过这样的情况,我有三个或四个类,但我们可以讨论两个类,以保持简单。
我在想一些简单的事情,比如:

class C
{
   public List<W> contentsW;

}

class W
{
  public C containerC;

}

这将工作的时刻,但我可以预见,必须编写相当数量的代码,以保持跟踪所有的引用和他们的有效性。我想在后面实现代码,只对容器进行浅刷新,对所有引用的类进行深刷新。是否有其他方法,其优点是什么?
编辑11/3:感谢所有的好答案和良好的讨论。我最终选择了乔普的答案,因为这最接近我想做的事情,但其他答案也有帮助。再次感谢!

bqucvtff

bqucvtff1#

如果你有Martin Fowler的重构书,就按照“将单向关联改为双向”重构。
如果你没有它,这里是你的类在重构后的样子:

class C
{
  // Don't to expose this publicly so that 
  // no one can get behind your back and change 
  // anything
  private List<W> contentsW; 

  public void Add(W theW)
  {
    theW.Container = this;
  }

  public void Remove(W theW)
  {
    theW.Container = null;
  }

  #region Only to be used by W
  internal void RemoveW(W theW)
  {
    // do nothing if C does not contain W
    if (!contentsW.Contains(theW))
       return; // or throw an exception if you consider this illegal
    contentsW.Remove(theW);
  }

  internal void AddW(W theW)
  {
    if (!contentW.Contains(theW))
      contentsW.Add(theW);
  }
  #endregion
}

class W
{
  private C containerC;

  public Container Container
  {
    get { return containerC; }
    set 
    { 
      if (containerC != null)
        containerC.RemoveW(this);
      containerC = value; 
      if (containerC != null)
        containerC.AddW(this);
    }
  }
}

请注意,我已将List<W>设置为私有。通过枚举器公开W的列表,而不是直接公开列表。
public String getWs(){ return this.ContentW.ToList();}
上面的代码正确地处理了所有权的转移。假设你有两个C的示例-- C1和C2 --以及W的示例-- W1和W2。

W1.Container = C1;
W2.Container = C2;

在上面的代码中,C1包含W1,C2包含W2。如果将W2重新分配给C1,

W2.Container = C1;

然后C2将有零个项目,C1将有两个项目- W1和W2。你可以有一个浮动的W

W2.Container = null;

在这种情况下,W2将从C1的列表中删除,它将没有容器。您还可以使用C的Add和Remove方法来操作W的容器-因此C1.Add(W2)将自动从其原始容器中删除W2并将其添加到新容器中。

iszxjhcz

iszxjhcz2#

我通常是这样做的:

class C
{
   private List<W> _contents = new List<W>();
   public IEnumerable<W> Contents
   {
      get { return _contents; }
   }

   public void Add(W item)
   {
      item.C = this;
      _contents.Add(item);
   }
}

因此,Contents属性是只读的,只能通过聚合方法添加项。

gcmastyq

gcmastyq3#

嗯,看起来你几乎已经掌握了,还有一个小问题--你必须能够在C中控制列表的添加。
例如,在一个实施例中,

class C
{
    private List<W> _contentsW;

    public List<W> Contents 
    {
        get { return _contentsw; }
    }

    public void AddToContents(W content);
    {
        content.Container = this;
        _contentsW.Add(content);
    }
}

为了检查,你只需要通过你的名单,我想:

foreach (var w in _contentsW)
{
    if (w.Container != this)
    {
        w.Container = this;
    }
}

我不确定这是不是你需要的。
请注意,可能有多个W示例具有相同的值,但可能具有不同的C容器。

kqlmhetl

kqlmhetl4#

扩大乔恩的答案。
如果W不应该让C存活,你可能需要弱引用。
此外,如果你想转移所有权,添加应该更复杂。

public void AddToContents(W content);
{  
   if(content.Container!=null) content.Container.RemoveFromContents(content);
    content.Container = this;
    _contentsW.Add(content);
}
eqoofvh9

eqoofvh95#

一个选择是实现System.System.Model.Model下的IContainerIComponent接口。C是容器,W是组件。然后ComponentCollection类将作为W示例的存储,IComponent.Site将提供到C的反向链接。

olmpazwi

olmpazwi6#

这是我使用的模式。

public class Parent {
    public string Name { get; set; }
    public IList<Child> Children { get { return ChildrenBidi; } set { ChildrenBidi.Set(value); } }
    private BidiChildList<Child, Parent> ChildrenBidi { get {
        return BidiChildList.Create(this, p => p._Children, c => c._Parent, (c, p) => c._Parent = p);
    } }
    internal IList<Child> _Children = new List<Child>();
}

public class Child {
    public string Name { get; set; }
    public Parent Parent { get { return ParentBidi.Get(); } set { ParentBidi.Set(value); } }
    private BidiParent<Child, Parent> ParentBidi { get {
        return BidiParent.Create(this, p => p._Children, () => _Parent, p => _Parent = p);
    } }
    internal Parent _Parent = null;
}

显然,我有类BidiParent<C, P>BidiChildList<C, P>,后者实现了IList<C>等。幕后更新是通过内部字段完成的,而来自使用此域模型的代码的更新是通过公共属性完成的。

相关问题