评论主题对象的面向对象设计

时间:2015-02-03 16:19:21

标签: java json oop enums

我试图找出设计类的最佳方法,它封装了JSON派生的注释。每个评论都针对特定主题,可以是整个文件,也可以是文件的一行。这是一个示例评论:

{
    "text":"This is my favorite line!",
    "path":"My file.txt",
    "line":42
    ...
}

如果主题是整体文件,则linenull

我希望Comment类有subject()方法,但我不确定设计CommentSubject类的最佳方法。这就是我到目前为止所拥有的:

import javax.json.JsonObject;

class Comment {
    private final JsonObject json;
    private final CommentSubject subject;

    public JsonObject json() { return json; }
    public CommentSubject subject() { return subject; }

    public Comment(JsonObject json) {
        ...
        this.json = json;
        subject = json.isNull("line") ? new FileSubject(this) :
            new LineSubject(this);
        ...
    }

    ...
}

abstract class CommentSubject {
    enum SubjectType {
        FILE, LINE
    }

    public abstract SubjectType type();
    public abstract String path();
    protected abstract Comment comment();
}

class FileSubject extends CommentSubject {
    private final Comment comment;
    private final String path;

    public FileSubject(Comment comment) {
        this.comment = comment;
        path = comment.json().getString("path");
    }

    public FileSubject(CommentSubject subject) {
        this(subject.comment());
    }

    @Override public SubjectType type() { return SubjectType.FILE; }
    @Override public String path() { return path; }
    @Override protected Comment comment() { return comment; }

    ...
}

class LineSubject extends CommentSubject {
    private final Comment comment;
    private final String path;
    private final int line;

    public LineSubject(Comment comment) {
        this.comment = comment;
        path = comment.json().getString("path");
        line = comment.json().getInt("line");
    }

    public LineSubject(CommentSubject subject) {
        this(subject.comment());
    }

    @Override public SubjectType type() { return SubjectType.LINE; }
    @Override public String path() { return path; }
    @Override protected Comment comment() { return comment; }

    public int line() { return line; }

    ...
}

客户端代码可能如下所示:

doSomething(CommentSubject subject) {
    if (subject.type() == SubjectType.LINE) {
        LineSubject line = new LineSubject(subject);
        ...
    }

    ...
}

但是,我不喜欢我的当前设计需要客户端代码中的新LineSubject对象这一事实:subjectline在上面的示例中是相同的,所以新的对象创建似乎浪费了空间。此外,为了将CommentSubject对象传递给另一个CommentSubject构造函数,如上面的客户端代码所示,所有主题都需要由comment()方法可访问的注释支持。我也不知道我对SubjectType enum的看法。

我想要的是Comment使用subject()方法并能够区分文件和线条主题。那里有更好的设计吗?

1 个答案:

答案 0 :(得分:1)

如果文件注释和行注释之间的唯一区别是文件注释没有行号,则可以将类层次结构折叠为单个类,并使行号可选(即返回{{ 1}}而不是Integer)。这将允许客户端程序区分文件和行注释,因为文件注释将返回行号的int

null

客户端可以编写如下内容:

public class CommentSubject {

    private final Integer line;
    private final String path;
    private final String comment;

    public String path() { return path; }
    public Integer line() { return line; }
    public Comment comment() { return comment; }

    public static CommentSubject forFile(String p, String c) {
        return new CommentSubject(p, null, c);
    }
    public static CommentSubject forLine(String p, int i, String c) {
        return new CommentSubject(p, i, c);
    }

    private CommentSubject(String p, Integer i, String c) {
        path = p;
        line = i;
        comment = c;
    }
}

如果您希望避免在客户端中进行有条件调度,您可以采用类似访问者的方式,并让doSomething(CommentSubject subject) { Integer optLine = subject.line(); if (optLine != null) { int line = optLine.intValue(); ... } ... } 回复您评论的处理者,如下所示:

CommentSubject

请注意评论,路径和行如何隐藏在interface CommentProcessor { void onFileComment(String path, String comment); void onLineComment(String path, int line, String comment); } public class CommentSubject { private final Integer line; private final String path; private final String comment; public void process(CommentProcessor p) { if (line != null) { p.onLineComment(path, line.intValue(), comment); } else { p.onFileComment(path, comment); } } public static CommentSubject forFile(String p, String c) { return new CommentSubject(p, null, c); } public static CommentSubject forLine(String p, int i, String c) { return new CommentSubject(p, i, c); } private CommentSubject(String p, Integer i, String c) { path = p; line = i; comment = c; } } 中。现在访问它们的唯一方法是传递CommentSubject的实例,该实例将收到适当类型的CommentProcessor的回调。