2013-01-09 25 views
0

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

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仅适用于正确和错误的问题。在这种情况下,这个问题应该关闭。

+0

我不认为这是一个非常适合#1。 Stackoverflow用于客观答案的问题,而不是“个人意见”。此外,我们的个人意见如何让您受益?你怎么知道我们的经历代表你的情况? – meriton

+0

你不必模拟一个C结构,你可以模拟一个C++结构并添加像'getAuthorNames'这样的辅助函数。另外请记住,Java对象是引用类型,不像C/C++/C#结构 –

+0

您的问题也非常广泛。是关于公共领域吗?缺乏防御性复制?并行类层次结构?适合执行验证的地方?不稳定的接口? – meriton

回答

4

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

了解规则和背后的原因。当你打破他们,理解后果。对你的工作有充分的理由。与发生的事情一起生活

例如,我认为不要在公共场合暴露数据的规则是绝对的 - 只要您正确地做到这一点。

你需要认识到你做错了。

事实上,你做了那个List引用final只是意味着引用不能被改变。引用引用的列表可以添加和删除元素。你必须让它不可变以达到你想要的。

如果不使其不变,则对传递给构造函数的引用所做的更改将反映在对象中。即使您将该参考设为私有,情况也是如此。你必须复制你传入的列表,使对象的状态真正独立。与其他对可变类型的引用相同,如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) { ... } 
} 
+0

你说得对。规则只是为了让你知道后果。如果你清楚知道后果并愿意承担责任,那也许很好。嗯... – Steve

0

我发现标准的getter/setters有时是不必要的冗长,但有办法解决这个问题。

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

例如

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(); 
    } 
} 
相关问题