我在下面有一个简单的类,它有一个IList类型的属性Pages
。
有一些选项可以实现此属性,可以是Array
或Collection
/ List
/偶ReadOnlyCollection
public class Book
{
private string[] _pages;
public Book(string[] pages)
{
_pages = pages;
}
public IList<string> Pages
{
get
{
return _pages;
//return new Collection<string>(_pages);
//return new List<string>(_pages);
//return new ReadOnlyCollection<string>(_pages);
}
}
}
在设计时,我不知道客户将使用该属性的哪些操作,但选择上述任何选项都会影响其客户。
如果客户使用Book
类,如下所示
var book = new Book(new[] {"A", "B"});
var pages = book.Pages;
pages[0] = "A2";
并非所有属性Pages
的实现选项都适用于客户端。
选项1:为页面// OK, it works
public IList<string> Pages
{
get
{
return _pages;
}
}
选项2:返回页面// KO, it throws an exception NotSupportedException Collection is read-only
public IList<string> Pages
{
get
{
return new Collection<string>(_pages);
}
}
选项3:返回页面列表// OK, it works
public IList<string> Pages
{
get
{
return new List<string>(_pages);
}
}
选项4:返回页面// KO, it throws an exception SystemException Collection is read-only
public IList<string> Pages
{
get
{
return new ReadOnlyCollection<string>(_pages);
}
}
我不认为客户端可能出错。任何人都可以给出一些解释并建议Page
的好类型吗?
答案 0 :(得分:3)
另一种选择是定义您自己的集合类型PageCollection
,并在Book
类中使用它。这样做的好处是,您可以隐藏集合实现方式的详细信息。这种方法的另一个优点是,您可以提供特殊的&#34;收集方法。
例如,你可以扩展现有的集合(它也可能是为Page
创建自定义类的好建议,而不是使用普通字符串:
public class PageCollection : List<Page>
{
// additional methods
}
您还可以包装现有的集合。这样做的好处是,您可以完全控制要为&#34;用户提供的方法。
public class PageCollection : IEnumerable<Page>
{
private List<Page> _innerCollection = new List<Page>();
public void RipOut(IEnumerable<Page> pages)
{
foreach (var page in pages)
{
_innerCollection.Remove(page);
}
}
// other methods
public IEnumerator<Page> GetEnumerator()
{
return _innerCollection.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
答案 1 :(得分:1)
如果我理解你的问题,你会问:如何在不知道如何使用课程的情况下设计课程?
答案是,通过添加您想要支持的功能来设计它。
在您的示例中: 你有一本书页。您是否希望用户能够转到第0页,将其删除,并将其替换为其他内容?如果是这样,请将其设为列表。如果没有,请将其设为ReadOnlyCollection。
我建议将属性公开为实际属性(List或ReadOnlyCollection),这样就可以明确表达允许的内容,并且没有客户端猜测它们是否可以替换页面。
答案 2 :(得分:1)
所以最后我来了这个设计。自定义PageCollection
具有添加/删除方法将允许我在里面添加验证行为。如果使用List<Page>
,则无法做到这一点。
本书现在公开IPageCollection
页面,其方法少于IList。
更新:以下是创建新界面的原因:
public class Page
{
}
public interface IPageCollection : IReadOnlyList<Page>
{
void Add(Page page);
void Remove(Page page);
}
public class PageCollection : IPageCollection
{
public PageCollection(IList<Page> pages)
: base(pages)
{
}
public void Add(Page page)
{
}
public void Remove(Page page)
{
}
...
}
public class Book
{
private readonly PageCollection _pages;
public Book(IList<Page> pages)
{
_pages = new PageCollection(pages);
}
public IPageCollection Pages
{
get { return _pages; }
}
}
(感谢约翰,托马斯......的建议)