在Java中模拟结构是一种好的方法吗?

时间:2013-01-09 01:37:26

标签: java

曾经为一家大型科技公司工作过。我们用Java编程。他们非常聪明,他们喜欢在Java中使用C / C ++模拟结构。为了使自己清楚,他们主张创建充当“数据持有者”的类:

public class BookInformation {
    public final List<String> authors;
    public final String bookTitle;
    public BookInformation(List<String> authors, String bookTitle) {
        this.authors = authors;
        this.bookTitle = bookTitle;
    }
    @Override
    public String toString() { ... }

    @Override
    public int hashCode() { ... }

    @Override
    public boolean equals(Object obj) { ... }
}

正如我们所看到的,这个类的目的只是保存数据。虽然我们违反了许多企业编程规则,例如不直接暴露类字段和防御性复制,但这种类确实获得了诸如简洁编码等好处。我们可以直接调用字段名称,而不是调用getter和setter。

让我烦恼的是,这种类很难维持和扩展。它很难维护,因为无法确保对象的状态是合法的。商业逻辑可能会说,一本书必须有一个标题和至少一个作者。但在现实世界中,对象可以有空标题,空标题,空作者列表或空作者列表,我们根本无法控制它。很难扩展。例如,如果更改数据源以分别为作者姓名提供名字,姓氏,该怎么办?我必须使用两个字符串列表而不是一个。更糟糕的是,数据结构的变化会影响和界面。由于我没有getAuthorNames()接口,我可能需要在很多地方更改代码。

我必须承认上述情况没有发生。我必须承认,所有代码都使用该类是在团队的控制之下,因此界面更改听起来并不像写给其他团队/公司那样糟糕。即使我们使用Java,纯OO语言,在企业级编码,也可以拥有这样的编码标准吗?

我知道可能没有“正确”的答案。我想听听个人意见。代表自己大声说话!

编辑:

行。我应该重新解释我的问题的核心:牺牲一些教科书编码规则以获得简单性是否明智?当代码库增长并且团队成长时,牺牲会让你失望吗?个人意见很重要,特别是来自聪明人,在很多情况下,没有正确或错误的问题,我们都只是遵循令人信服的意见。对不起Stackoverflow只针对正确和错误的问题而设计。在这种情况下,这个问题应该被关闭。

2 个答案:

答案 0 :(得分:4)

我认为这是一个正确的答案:如果它适合你,那就去吧。没有风格警察在等着逮捕你。

了解规则及其背后的原因。当你打破它们时,要了解其后果。对你所做的事情有充分的理由。与发生的事情一起生活。

例如,我不认为永远不公开公开数据的规则必须是绝对的 - 只要你做得恰当。

你需要意识到你做错了。

您将List引用设为final的事实意味着无法更改引用。引用引用的List可以添加和删除元素。你必须让它变得无法实现你想要的东西。

如果不使其不可变,则对传递给构造函数的引用所做的更改将反映在对象中。即使您将该引用设为私有,也是如此。您必须复制传入的List,以使对象的状态真正独立。与其他对可变类型的引用相同,如Date。

它适用于String,因为它是不可变的。

还有一件事:应该是equals(),而不是Equals()。案例在Java中很重要。

public final class BookInformation {
    public final List<String> authors;
    public final String bookTitle;
    public final Date publicationDate;

    public BookInformation(List<String> authors, String bookTitle, Date publicationDate) {
        this.authors = Collections.unmodifiableList((authors == null) ? new ArrayList<String>() : authors);
        this.bookTitle = (StringUtils.isBlank(bookTitle) ? "" : bookTitle);
        this.publicationDate = ((publicationDate == null) ? new Date() : new Date(publicationDate.getTime()));
    }
    @Override
    public String toString() { ... }

    @Override
    public int hashCode() { ... }

    @Override

   public boolean equals(Object obj) { ... }
}

答案 1 :(得分:0)

我发现标准的getter / setter有时会不必要地冗长,但有很多方法可以解决这个问题。

例如,您可以使用与字段名称相同的getter或setter,并且可以创建比直接访问字段更简洁的操作方法。

e.g。

public class BookInformation {
    private final Set<String> authors = new LinkedHashSet<>();
    private final String bookTitle;

    public BookInformation(List<String> authors, String bookTitle) {
        assert authors != null;
        assert bookTitle != null;

        for(String author: authors) addAuthor(author);
        this.bookTitle = bookTitle;
    }

    public String bookTitle() { return bookTitle; }

    // get all the authors without needing a defensive copy.
    // for(int i = 0, len = bookInfo.authorCount(); i < len; i++) {
    //     String name = bookInfo.author(i);

    public int authorCount() { return authors.size(); }
    public String author(int n) { return authors.get(n); }

    public void addAuthor(String name) {
        assert name != null
        authors.add(name);
    }

class AuthorCounter {
    private final ConcurrentMap<String, AtomicInteger> authorCountMap =
                  new ConcurrentHashMap<>();

    public void addAuthor(String name) {
        authorCountMap.putIfAbsent(name, new AtomicInteger());
    }

    public void incrCountFor(String name) {
        authorCountMap.get(name).incrementAndGet();
    }

    public int countForAuthor(String name) {
        AtomicInteger ai = authorCountMap.get(name);
        return ai == null ? 0 : ai.get();
    }
}