用于为书籍建模的Java类

时间:2015-11-12 13:56:37

标签: java oop inheritance arraylist

在提出问题之前,我必须说这是家庭作业,我只是在寻找如何实现一本书的模型的想法。

一本书有一个标题和许多章节,每一章都有一个标题和多个子章节。每个子章节都有一个标题和一个段落列表。每个段落都可以有一个数字和一个文本。我希望在OOP中实现以下功能:添加/删除:章节,子章节和段落并显示本书。 我在为班级找到正确的结构时遇到了一些麻烦。

这就是我考虑实施它的方式,但它似乎有点冗余和复杂。有没有更简单,更正确的方法呢?

public class Element<T> {
        int nr;
        String Title;
        ArrayList<T> x = new ArrayList<T>();

        Element() {
            nr = 0;
            Title = "";
        }

        public void removeFromElement(int index) {
            if (index <= 0 && index > x.size())
                System.out.println("The chapter doesn't exist");
            else {
                x.remove(index);
                System.out.println("Succesful deletion");
            }
        }

        public void addToElement(T elem) {
            x.add(elem);
        }
    }

    public class Paragraph {
    int nr;
    String text;
    }

    public class Subchapter extends Element<Paragraph> {
    }

    public class Chapter extends Element<Subchapter> {
    }

    public class Book extends Element<Chapter> {
    }

4 个答案:

答案 0 :(得分:5)

你的第一种方法很不错,但没有考虑进化的可能性。

如果我们要求您添加段落的0-n引号(或其他任何内容)的可能性,会发生什么? 如果我们要求您在书中添加一个不能包含子章节的章节,会发生什么?

这需要做出巨大改变。你应该看一下composite pattern

遵循这种模式,就变革而言,你会更加灵活。

当您考虑OOP时,您必须始终牢记接口可以在您设计代码的方式中发挥重要作用。 许多这些问题已经解决并具有常规解决方案(设计模式)。你应该花时间学习最常见的。它肯定会改变你的编码方式。

(“首先设计模式头”将是一本好书。)

此外,OOP最重要的特性之一是封装。 这提供了一种非常强大的方法来控制类的“属性”可访问性。 你必须使用它。首先在类的属性上添加privateprotected修饰符,然后创建访问/修改这些属性所需的getters / setter。

需要注意的另一件事: 您不应使用System.out.println()方法来记录您的代码。使用日志API(例如log4j)和例外。

    public void removeFromElement(int index) throws ChapterNotFoundException{
        if (index <= 0 && index > x.size()){
            throw new ChapterNotFoundException(String.format("Chapter %s does not exist", index));
        }

        x.remove(index);
        logger.info(String.format("Chapter %s has been removed", index));
    }

答案 1 :(得分:3)

这实际上是不正确的设计。 (但我喜欢你对最小化代码编写的看法)

本书不是通过章节或“章节元素”扩展的。这本书包含章节,也可以包含/做其他事情。

因此,正确的设计是最简单的设计

public class Book{
    private String title;
    private List<Chapter> chapters;
}
//other classes would look similar

这种方法更加稳定,并且可以在将来轻松修改(甚至替换)。

这个“现象”也有名字,它是Composition over inheritance

答案 2 :(得分:2)

您的整体模型实际上具有相当大的意义。您已经识别出重复的代码并将其分成一个类。您对泛型的使用有助于保持清洁。是否值得明确地分离出树的层(因为这就是本质上的),如Subchapters,Chapters等取决于您的确切要求。

定义树节点和叶子可能更简单,但如果你确实需要在每一层都有不同的行为,并且不需要灵活地添加或删除更多层,那么这很好。例如,如果您将拥有一个带有Omnibus的综合 - > Book>&gt; Chapter-&gt; Subchapter-&gt; Paragraph,或者一本书,Book-&gt; Chapter-&gt; Section-&gt; Subchapter-&gt; Paragraph 。你的模型可以支持吗?如果不是,它需要吗?

某些命名可能更清晰(例如nr作为数字)或不遵循样式约定(标题应为标题)。

我说的主要错误是将数字存储在对象内部。这很脆弱,因为这意味着你不断更新它,因为添加,删除等等。

您只需查看父级中的位置即可找到该号码。基本上你是在重复这些信息。

正如Grégory在评论中指出的,所有变量都应该是私有的,并通过getter和setter访问。

答案 3 :(得分:1)

你的设计很好。代码中有一些错误;我建议写一些单元测试来找到它们(提示:尝试删除页面)。

我编写的软件用于处理多种语言的书籍(Java,Python,Groovy),并发现它比它看起来更难。问题是所有元素(书,章,子章,段落)都有许多共同的特征,但有细微的差别。其中大多数是特定类型的其他元素的容器(因此一本书由章节而不是段落组成)。只有段落不是容器。它们都有文本(段落的标题或文本),但文本的语义不同。另外,子章节的标题没有意义,或者是吗?

这使得很难找到一个好的API来处理所有角落的情况而没有太多重复的代码,特别是在像你没有mixins的Java这样的语言中。