2013-01-09 24 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(); 
    } 
} 
相關問題