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

Java 面向对象的评论主题对象设计,java,json,oop,enums,Java,Json,Oop,Enums,我试图找出设计类的最佳方法,该类封装JSON派生的注释。每一条评论都针对一个特定的主题,可以是一个文件整体,也可以是一行文件。下面是一个示例注释: { "text":"This is my favorite line!", "path":"My file.txt", "line":42 ... } 如果主题是一个整体文件,行为null 我希望Comment类具有subject()方法,但我不确定设计CommentSubject类的最佳方法。以下是我目前掌握的情况

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

{
    "text":"This is my favorite line!",
    "path":"My file.txt",
    "line":42
    ...
}
如果主题是一个整体文件,
null

我希望
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);
        ...
    }

    ...
}
doSomething(CommentSubject subject) {
    Integer optLine = subject.line();
    if (optLine != null) {
        int line = optLine.intValue();
        ...
    }
    ...
}
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;
    }
}
但是,我不喜欢我当前的设计在客户端代码中需要一个新的
LineSubject
对象:
subject
line
在上面的示例中是相同的,因此创建新对象似乎是浪费空间。此外,为了将一个
CommentSubject
对象传递给另一个
CommentSubject
构造函数,就像上面的客户机代码一样,所有主题都需要有一个可通过
comment()
方法访问的注释作为支持。我也不知道我对
SubjectType
enum
的看法


我想要的是
Comment
有一个
subject()
方法,并且能够区分文件主题和行主题。有更好的设计吗?

如果文件注释和行注释之间的唯一区别是文件注释没有行号,则可以将类层次结构折叠为单个类,并使行号可选(即返回
整数而不是
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) {
    if (subject.type() == SubjectType.LINE) {
        LineSubject line = new LineSubject(subject);
        ...
    }

    ...
}
doSomething(CommentSubject subject) {
    Integer optLine = subject.line();
    if (optLine != null) {
        int line = optLine.intValue();
        ...
    }
    ...
}
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
回调您的评论处理者,如下所示:

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

    ...
}
doSomething(CommentSubject subject) {
    Integer optLine = subject.line();
    if (optLine != null) {
        int line = optLine.intValue();
        ...
    }
    ...
}
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
的实例,该实例将接收相应类型的
CommentSubject
的回调