对于这个残暴的头衔感到抱歉,但我想不出更好的措辞。我将尝试用一个例子来更清楚地说明这一点(这不是我实际上要解决的问题,但我不想讨论特定问题的细节)。
假设我想模仿论坛式的讨论。通常,主题代表要讨论的内容(消息,照片等),评论代表人们对该主题的评论。所以,在非常抽象的层面上,我们有:
Topic
+ title
+ comments: List<Comment>
Comment
+ text
注意:我在这里混合使用类似Java的语法,因为我正在寻找Java解决方案,但任何适用于语义与Java语言相似的语言的解决方案可能都会很好。
这个简单的模型足以用于某个主题及其注释的一般用途表示。但在某些情况下,我希望有更多信息的主题和评论。例如,对于所有评论都是“创作”的网站(即他们有作者......他们不能匿名),我想要:
AuthoredTopic < Topic
+ author
+ comments: List<AuthoredComment>
AuthoredComment < Comment
+ author
基本上,我希望有更多专业类型的主题,其中包含更多特殊类型的注释,但它们仍然可以被视为抽象主题和评论。以一种非常基本的方式来看待它:一个创作的主题有一个作者,但它仍然是一个主题,其创作的评论仍然是评论。
现在,在任何人查看伪类规范的癫痫发作之前,comments
attribure是只读列表(又名不可变= D)。如果不是,那么设计将是简单的并且简单地破坏,因为可以向AuthoredTopic添加任何类型的评论。但如果它是不可变的,那么你可以说List<AuthoredComment>
是 List<Comment>
,因此AuthoredComment可能是Comment的有效子类型。
现在,我知道Java没有泛型类型的协方差,所以不能说List<AuthoredComment>
是一个子类型List<Comment>
,这是一个耻辱,也可能是我'的原因我发现很难设计/实现这个。
那么,我该如何解决这个问题?
我是从一个完全错误的方式接近这个吗?
为了使事情变得更糟(或者说更有趣),可能会进一步对主题和评论进行子类化。例如:
YouTubeVideoTopic < AuthoredTopic
+ video
+ votes
+ comments: List<YouTubeComment>
YouTubeComment < AuthoredComment
+ votes
最后,虽然Topic
和AuthoredTopic
可能最终成为接口或抽象类,但如果像YouTubeVideoTopic
这样的具体类可以为它们添加注释(它的addComment
方法应该收到YouTube评论论点。)
我现在将解释我为解决这个问题而尝试的两种方法,它们都没有真正成功或令人信服。
基本主题类有一个抽象的getComments: List<Comment>
方法,而AuthoredTopic类添加了一个抽象的getAuthoredComments: List<AuthoredComment>
方法,最后像YouTubeVideoTopic这样的叶子类具有一个具体的getYouTubeComments: List<YouTubeComment>
,同时也实现了它们父母的*评论方法。
代码:
abstract class Topic {
private String title;
public Topic(String title) {
this.title = title;
}
public abstract List<Comment> getComments();
// Other getters...
}
class Comment {
private String text;
// Constructor & getters
}
abstract class AuthoredTopic extends Topic {
private String author;
public AuthoredTopic(String title, String author) {
super(title);
this.author = author;
}
public abstract List<AuthoredComment> getAuthoredComments();
@Override
public List<Comment> getComments() {
return Collections.<Comment> unmodifiableList(getAuthoredComments());
}
}
class AuthoredComment extends Comment {
private String author;
}
class YouTubeVideoTopic extends AuthoredTopic {
int votes;
String video; // Yeah.. 'video' is a string for now...
List<YouTubeComment> comments = new ArrayList<YouTubeComment>();
public YouTubeVideoTopic(String title, String author) {
super(title, author);
}
public List<YouTubeComment> getYouTubeComments() {
return Collections.unmodifiableList(comments);
}
@Override
public List<AuthoredComment> getAuthoredComments() {
return Collections.<AuthoredComment> unmodifiableList(comments);
}
public void addComment(YouTubeComment comment) {
comments.add(comment);
}
}
class YouTubeComment extends AuthoredComment {
int votes;
}
它完成了工作,但你可以看到它是一个非常难看的解决方案。不是很干。像YouTubeVideoTopic这样的叶子类必须实现很多东西。此外,嵌套的Topic子类最终会有多个get * Comments,它们只是设计中的噪声。
我发现这种方法更容易实现:
class Topic<CommentT extends Comment> {
private String title;
private List<CommentT> comments = new ArrayList<CommentT>();
public Topic(String title) {
this.title = title;
}
public List<CommentT> getComments() {
return Collections.unmodifiableList(comments);
}
public void addComment(CommentT comment) {
comments.add(comment);
}
}
class Comment {
private String text;
// Constructor & getters
}
class AuthoredTopic<CommentT extends AuthoredComment> extends
Topic<CommentT> {
String author;
public AuthoredTopic(String title, String author) {
super(title);
this.author = author;
}
public String getAuthor() {
return author;
}
}
class AuthoredComment extends Comment {
private String author;
}
class YouTubeVideoTopic extends AuthoredTopic<YouTubeComment> {
int votes;
String video; // Yeah.. 'video' is a string for now...
public YouTubeVideoTopic(String title, String author) {
super(title, author);
}
}
class YouTubeComment extends AuthoredComment {
int votes;
}
但是,它的缺点是类型参数“泄漏”到使用此clases的代码中,即使通配符可以使字符开销非常小:
List<Topic<?>> t = getAllTopics();
Topic
不应该有类型参数。一个主题只是有评论。在主题层面,只要它们是评论,它的评论类型就没有关系;它们的类型是否是同质的甚至无关紧要(Topic的某些子类,如YouTubeVideoTopic可能只有YouTubeComments,但在基本主题级别无关紧要。)
答案 0 :(得分:2)
这称为并行层次结构。 c2 wiki有一个很好的讨论。谷歌搜索也带来了好处。
我同意基于通用的方法更清晰。
答案 1 :(得分:0)
让getComments
方法返回List<? extends Comment>
。像这样:
public class Topic {
public List<? extends Comment> getComments() {
return new ArrayList<Comment>();
}
}
public class Comment {
}
public class AuthoredTopic extends Topic {
@Override
public List<? extends Comment> getComments() {
return new ArrayList<AuthoredComment>();
}
}
public class AuthoredComment extends Comment {
}