公共只读List <t>糟糕的设计?

时间:2015-12-01 09:03:16

标签: c# oop software-design

我目前正在编写一个应用程序,它建立与某种服务的连接,以几个DataTable对象的形式获取数据,然后应该向用户显示它。
为了存储数据,我创建了一个名为DataStorage的类,其中包含List<DataTable>。其他类需要能够编辑此List,例如添加所需的对象或在用户发现不需要时删除它们。如果我需要一组全新的数据,我也必须能够清除它 我可以为此提供DataStorage方法,但由于List<T>已经提供了这些,我认为没有必要像这样封装它。所以我做了readonly以确保没有人尝试分配新对象 - 或者更糟糕的是,null - 并创建了访问修饰符public。 这种设计是否可以接受,或者我应该始终保护字段免受直接访问,无论如何?

3 个答案:

答案 0 :(得分:6)

一般来说,你应该总是采用最通用的类​​型来减少任何紧耦合,并且只提供你实际需要访问的那些成员。在某些情况下说过这一点后,最好使用ICollection来提供对AddRemoveClear等基本方法的访问权限。

然而,使集合readonly或甚至更好的Get-only属性可能是一个好主意,并且没有任何可以说对此。

答案 1 :(得分:2)

我们应该对public非常小心,这意味着public - 无论如何。 你让任何一个班级都以这种方式行事吗?

  public class Offender {
    ...
    public void Offend(YourClass value) {
      ...
      // In the middle of my routine I've ruined your class
      value.Data.Clear();
      value.Data.Add(someStuff);
      ...
    }
  }

我建议仅将完全访问权限限制为Data到受信任的类:

  public class YourClass {
    // Approved classes (i.e. from your routine) can write, delete, clear... 
    internal readonly List<Data> m_Data = new List<Data>();

    // All the other can only read 
    public IReadOnlyList<Data> Data {
      get {
        return m_Data;
      }
    }
    ...
    // If you let (in some cases) add, delete, clear to untrusted class 
    // just add appropriate methods:
    public void Add(Data data) {
      // Here you can validate the provided data, check conditions, state etc.
    }
  }

答案 2 :(得分:0)

如果您要发布具有添加/删除功能的集合,那么最好覆盖Collection<T>(或ObservableCollection<T>)类,这与List<T>非常相似,但您可以覆盖并因此控制添加/删除/替换操作。是的,你可以通过get-only属性公开它。

public class MyClass
{
    private MyCollection myCollection = new MyCollection();

    public IList<MyElement> Collection { get { return myCollection; } }
}

internal class MyCollection: Collection<MyElement>
{
    // by overriding InsertItem you can control Add and Insert
    protected override InsertItem(int index, MyElement item)
    {
        if (CheckItem(item))
            base.InsertItem(index, item);
        throw new ArgumentException("blah");
    }

    // similarly, you can override RemoveItem to control Remove and RemoveAt,
    // and SetItem to control the setting by the indexer (this[])
}