gpt4 book ai didi

java - 如何使用更具体的对象家族(A' < : A has many B' <: B)?)扩展对象家族(A 有很多 B)

转载 作者:行者123 更新时间:2023-11-30 04:58:25 25 4
gpt4 key购买 nike

对不起这个残酷的标题,但我想不出更好的措辞方式。我将尝试通过一个示例更清楚地说明这一点(这不是我实际上要解决的问题,但我不想深入讨论特定于问题的细节)。

假设我想为类似论坛的讨论建模。通常,主题代表要讨论的内容(消息、照片等),评论代表人们对该主题的评论。所以,在一个非常抽象的层面上,我们有:

Topic
+ title
+ comments: List<Comment>

Comment
+ text

注:我在这里混合了类似 Java 的语法,因为我正在寻找一种 Java 解决方案,但是任何适合与 Java 具有相似语义的语言的解决方案都可能是好的。

假设这个简单的模型对于主题及其评论的一些通用表示已经足够了。但在某些情况下,我希望有更多信息的主题和评论。例如,对于一个所有评论都是“作者”的网站(即他们有一个作者......他们不能是匿名的),我想要:
AuthoredTopic < Topic
+ author
+ comments: List<AuthoredComment>

AuthoredComment < Comment
+ author

所以基本上,我希望有更专业类型的主题,其中包含更专业类型的评论,但它们仍然可以分别被视为抽象主题和评论。以一种非常基本的方式看待它:一个创作的主题有一个作者,但它仍然是一个主题,它的创作评论仍然是评论。

现在,在任何人读到那个伪类规范之前, comments属性是一个只读列表(又名不可变 =D)。如果不是这样,设计将是简单而简单的,因为可以将任何类型的评论添加到 AuthoredTopic。但如果它是不可变的,那么您可以说 List<AuthoredComment>List<Comment> ,因此 AuthoredComment 可能是 Comment 的有效子类型。

现在,我知道 Java 没有泛型类型的协变,所以不能说 List<AuthoredComment>是一个子类型 List<Comment> ,这很遗憾,并且可能也是我发现设计/实现它非常复杂的原因。

那么,我该如何解决呢?

我是否以完全错误的方式处理这个问题?

更糟糕的是(或者说更有趣),主题和评论可能会有进一步的子类化。例如:
YouTubeVideoTopic < AuthoredTopic
+ video
+ votes
+ comments: List<YouTubeComment>

YouTubeComment < AuthoredComment
+ votes

最后,虽然 TopicAuthoredTopic可能最终成为接口(interface)或抽象类,如果对于像 YouTubeVideoTopic 这样的具体类,那就太好了可以向它们添加评论(它的 addComment 方法应该接收一个 YouTubeComment 参数)。

我现在将解释我尝试解决这个问题的两种方法,它们都没有真正成功或令人信服。

方法一:有多种方法返回评论

基础主题类有一个抽象 getComments: List<Comment>方法,而 AuthoredTopic 类添加一个抽象 getAuthoredComments: List<AuthoredComment>方法,最后像 YouTubeVideoTopic 这样的叶子类有一个具体的 getYouTubeComments: List<YouTubeComment>同时还实现了他们 parent 的 get*Comments 方法。

代码:

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,这些在设计中只是噪音。

方法 2:添加泛型类型参数

我发现这种方法更容易实现:

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;
}

但是,它的缺点是类型参数“泄漏”到使用这个类的代码中,即使通配符可以使字符开销非常小:
List<Topic<?>> t = getAllTopics();
Topic不应该有类型参数。一个主题只是有评论。没关系,在主题层面,它的评论是什么类型的,只要是评论即可;它们的类型是否同质甚至都没有关系(主题的某些子类,例如 YouTubeVideoTopic 可能只有 YouTubeComments,但这在基本主题级别并不重要)。

最佳答案

这称为并行层次结构。 c2 wiki有一个很好的讨论。谷歌搜索也带来了好东西。

我同意基于通用的方法更清洁。

关于java - 如何使用更具体的对象家族(A' < : A has many B' <: B)?)扩展对象家族(A 有很多 B),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7735596/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com