何时应该封装泛型类型

本文关键字:泛型类型 封装 何时应 | 更新日期: 2023-09-27 18:07:14

我看到许多人建议您应该用更接近您的领域的类封装泛型类型,例如Steve和Nat在《成长中的面向对象软件,由测试指导》中建议:

我们的经验法则是,我们试图限制使用泛型传递类型[…]。特别是当应用于集合时,我们将其视为一种复制形式。这是一个暗示,有一个领域的概念,应该提取到一个类型。

一般来说,什么时候做这样的事情是一个好主意…

class PersonList : List<Person>

. .而不是直接使用List<Person> ?

何时应该封装泛型类型

您正在寻找的是Java或c#的typedef运算符。

不幸的是,子类化方法不能很好地替代typedef

下面的文章"Java理论与实践:伪类型定义反模式"详细解释了原因。

我将逐字逐句地把那篇文章的结论抄在这里:

伪类型定义反模式的动机很简单足够了——开发人员想要一种定义更紧凑类型的方法标识符,特别是泛型使类型标识符更加详细的。问题是,这种习惯用法在使用它的代码和该代码的客户端,抑制了重用。你可能不喜欢泛型类型标识符的冗长,但这是这不是解决问题的办法。

我不同意这种观点。List<Person>PersonList一样是一种类型。人员列表的领域概念也被封装在其中。如果你问我,我会说最好尽可能多地使用泛型,除非使用它们限制了你(见下文)或使代码难以理解。例如,一个在PersonList上工作的函数将比在List<Person>上工作的函数更难泛化,如果你甚至注意到它正在做一些通用的事情。

也就是说,特别是在Java中,泛型有一个限制,使它们不那么吸引人。由于类型擦除,当涉及到类型的静态方法/成员时,您不能完全利用泛型,并且您可能需要提取非泛型的特定类型,以便能够将其用于某些事情。底线是,在Java中,如果允许您保持类型安全,那么在许多情况下您确实需要提取特定类型。

因为让类型参数保持原样并不是真正的DRY。考虑这个类:

class Muffin {
    List<string> _peopleWhoLikeMuffins = new List<string>();
    public Muffin(List<string> peopleWhoLikeMuffins) {
        _peopleWhoLikeMuffins = peopleWhoLikeMuffins);
    }
    public void AddMuffinLiker(string p) {
        _peopleWhoLikeMuffins.Add(p);
    } 
}

它真的很短,只包含基本的功能,但是我不得不使用string——泛型类型参数——四次。而且永远都是一样的。如果我决定稍后更改类型,我将不得不替换所有四个出现。

在现实世界中,我们谈论的是数百,而不是4。因此,总是将其封装并不是一件容易的事,但这绝对值得考虑。

现在,我的例子不是很好(不仅仅是因为愚蠢的名字),但是你明白了——你将有很多字段和变量声明和实例化,而且每次你都必须传递一个类型参数,这个参数在你的程序中总是相同的代码库,除非你的其他类也是泛型的。

这样做的另一个好处是,如果你需要向你的集合添加一些额外的状态/行为,你会少做很多工作。

话虽如此,我自己并不经常使用这种抽象。