【问题标题】:Object-oriented design for comment subject object评论主题对象的面向对象设计
【发布时间】:2015-02-03 16:19:20
【问题描述】:

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

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

如果主题是一个整体的文件,line 就是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);
        ...
    }

    ...
}

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

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

【问题讨论】:

    标签: java json oop enums


    【解决方案1】:

    如果文件注释和行注释之间的唯一区别是文件注释没有行号,则可以将类层次结构折叠为单个类,并使行号可选(即返回@987654321 @ 而不是 int)。这将让客户端程序区分文件和行 cmets,因为文件 cmets 将返回 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 回调您的 cmets 的处理器,如下所示:

    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 的回调。

    【讨论】:

      猜你喜欢
      • 2014-06-19
      • 2010-12-27
      • 1970-01-01
      • 1970-01-01
      • 2013-09-05
      • 2016-01-19
      • 1970-01-01
      相关资源
      最近更新 更多