簡體   English   中英

在Java中哪個更好:將字段存儲兩次,或在基類中將其存儲為受保護的字段?

[英]Which is preferable in Java: storing a field twice, or storing it as protected in the base class?

我很少使用繼承,但是當我這樣做時,有時會遇到以下問題。 鑒於:

  • 我想在父類構造函數中注入一個對象,例如Logger
  • 給定父級和子級都需要使用此字段。
  • 鑒於我不想將這個領域暴露給外界(沒有吸氣劑)。

我已經看到以兩種不同的方式解決了這個問題:

class ChildClass extends ParentClass {
  private Logger logger;
  public ChildClass(Logger logger) {
    super(logger);
    this.logger = logger;
  }
}

class ParentClass {
  private Logger logger;
  public ParentClass(Logger logger) {
    this.logger = logger;
  }
}

要么:

class ChildClass extends ParentClasss {
  public ChildClass(Logger logger) {
    super(logger);
  }
}

class ParentClass {
  protected Logger logger;
  public ParentClass(Logger logger) {
    this.logger = logger;
  }
}

我猜另一個選擇是ParentClass的受保護的getter,但是我從未遇到過。

就我個人而言,我更傾向於第二種方法,其理由是較小的數據大小勝過封裝,但是我經常在野外遇到第一種版本。 有沒有更可取的方式來做到這一點?

我認為沒有絕對優選的方法,但是總的來說,如果您知道記錄器可能是子類所需要的(就像在這種情況下一樣),則應該通過保護字段或添加一個字段來使其可訪問。受保護的吸氣劑。 有人會說添加吸氣劑是可取的。

您看到“野外”重復字段的原因之一是因為子類是第二個編寫的,修改父類並非總是可能的。

從設計和性能的角度來看,第二個選項更好,假設在父類中需要記錄器。 具有兩個包含相同值的屬性可能會造成混淆,並占用更多空間。 (僅當創建大量實例時,后者才有意義。)

然而:

  • 我會在父類中將其聲明為private ,並提供一個protected final getter方法。
  • 如果確實將其聲明為父類的protected屬性,則還應該將其定為final
  • 如果使用的是標准日志記錄API之一,則通常的做法是讓對象實例化其自己的記錄器; 例如與Log4j

      this.logger = Logger.getLogger(this.getClass()); 

這些都是相對較小的問題,但是(IIRC)默認PMD規則集包含有關protected屬性的規則。

...但是我經常在野外遇到第一個版本。

是的,很多原始代碼並不完美,而且我認為這些是相對較小的問題。

跟進

說兩個字段都是最終的。 在第一種情況下,您是否認為編譯器會足夠聰明,以找出指針始終是相同的並將它們折疊到同一字段中?

不。我認為編譯器不會這樣做:

  • 任何優化都必須面對屬性的反射訪問(甚至更新)。 在這種情況下,反射代碼將需要了解優化,並將字段的一個版本的請求映射到另一個。

  • 在大多數情況下,這種優化的收益很小,而JIT編譯器弄清楚該優化是有效的,其CPU成本將是巨大的。

(請記住,此優化只能由JIT編譯器執行。字節碼編譯器沒有足夠的信息來進行優化。具體地說,它不知道類構造函數的最終代碼是什么。請注意,除非存在大量有關對象的實例,否則節省的空間將是微不足道的。)

但是,我使用Guice已有一段時間了,這似乎是注入記錄器而不是依賴靜態工廠的一種標准做法。

我認為這是Guice特有的習慣用法。 普通的Java應用程序/庫在我的經驗中很少將記錄器作為參數。

我還將使用第二種方法。

我不確定您為什么如此關注內存占用,但是兩種方法之間的區別可以忽略不計。 從技術上講,您不會兩次存儲 logger 在Java中,所有對象變量都是指針 因此,在第一種情況下, ParentClassChildClass都指向同一logger實例。

第二種方法是具有繼承優勢(共享功能和屬性)的經典示例。

老實說,這是一個完全由您決定的設計決策,對內存占用量都沒有真正的重大影響,但是第二種方法比第一種方法更多地利用了OOP原理。

如果您絕對不想將字段公開給外界,則需要將其設置為private ,因為即使protected字段也對其包的成員(以及任何子類)可見。 但是,在Logger的情況下,這可能會過大。 繼承可能更易於理解/維護實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM