曾经为一家大型科技公司工作过。我们用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只针对正确和错误的问题而设计。在这种情况下,这个问题应该被关闭。
答案 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();
}
}