簡體   English   中英

如何設計一個持有java.lang.String的不可變值類?

[英]How to design an immutable value class holding java.lang.String?

目的

創建一個用作String對象的不可變列表的類。

方法

我決定利用Google GuavaImmutableList <E>集合,而不是將簡單的List <E>Collections.unmodifiableList(List <?擴展T>列表)包裝在一起,因為我知道這避免了對支持List <E的不必要的並發檢查> ,它不知道是否被包裝(來源: ImmutableCollectionsExplained )。

要求

  • 具有“值所有者”的類,可在線程之間使用
  • 創建后,不允許任何代碼更改內部值

物超所值

  • 該類應實現Iterable <E>以按創建順序遍歷值
  • 對於一組給定的String,應該只有一個類。

嘗試次數

盡管可以進行更多組合,但是在此進行了一些嘗試。 原諒幽默的演繹。

嘗試1(包括用法示例)

import java.util.List;
import com.google.common.collect.ImmutableList;
class BritnetSpearsSpellings implements Iterable<String> {
  public static BritnetSpearsSpellings of(String... spellings) {
    BritnetSpearsSpellings britneySpears = new BritnetSpearsSpellings();
    britneySpears.spellings = ImmutableList.copyOf(spellings);
    return britneySpears;
  }
  private List<String> spellings;
  private BritnetSpearsSpellings() {
  }
  public List<String> getSpellings() {
    return spellings;
  }
}
@Override
public Iterator<String> iterator() {
  return spellings.iterator();
}
public class Usage {
  public static void main(String[] args) {
    for (String sepllin : BritnetSpearsSpellings.of("Brittany Spears", "Brittney Spears", "Britany Spears"))
      System.out.printf("You spel Britni like so: %s%n", sepllin);
    }
  }
}

嘗試#2

class BritnetSpearsSpellings implements Iterable<String> {
  public static BritnetSpearsSpellings of(String... spellings) {
    BritnetSpearsSpellings britneySpears = new BritnetSpearsSpellings();
    britneySpears.spellings = ImmutableList.copyOf(spellings);
    return britneySpears;
  }
  private ImmutableList<String> spellings;
  private BritnetSpearsSpellings() {
  }
  public ImmutableList<String> getSpellings() {
    return spellings;
  }
  @Override
  public Iterator<String> iterator() {
    return spellings.iterator();
  }
}

嘗試#3

class BritnetSpearsSpellings implements Iterable<String> {
  public static BritnetSpearsSpellings of(String... spellings) {
    BritnetSpearsSpellings britneySpears = new BritnetSpearsSpellings(ImmutableList.copyOf(spellings));
    return britneySpears;
  }
  private final ImmutableList<String> spellings;
  private BritnetSpearsSpellings(ImmutableList<String> spellings) {
    this.spellings = spellings;
  }
  public ImmutableList<String> getSpellings() {
    return spellings;
  }
  @Override
  public Iterator<String> iterator() {
    return spellings.iterator();
  }
}

差異摘要

  • 1將List <E>保留在公共接口中,記錄了JavaDoc中的不變性。

  • 2將所有內容存儲並公開為Google GuavaImmutableList <E>

  • 3使內部引用保持最終狀態,但以創建專門的構造函數為代價,可能會使靜態工廠方法初始化在沒有其他初始化選項的情況下看起來很愚蠢(實際上存在於真實類中)

請幫助我在這些實現方式中選擇一種,並在選擇時提供您的推理依據。

我認為方法2的主要缺點是客戶需要具有專門的Google Guava類型的認知/可見性,也許他們不應該嗎?

顯然,我認為#3是最佳選擇。 final強制並記錄了類(該字段)的不可變性,不僅限於List本身是不可變的事實。

在getter中使用某些Javadoc公開List還是實際的ImmutableList是另一回事。 我已經看到了這樣的觀點,即返回ImmutableList清楚地說明意圖,但是,您仍然將自己綁定到實現上,而不是接口上,這是一個很低的水平,將來可能需要更改(即使不可變性通常是“ ”)。 因此,對於您的應用程序而言,它不僅僅是一個用例,而是更多的全局設計選擇。 如果您確實使用ImmutableList ,那么我認為這對客戶端不是一個真正的問題,名稱是顯式的,可以通過您的IDE輕松地看到它是List的實現,如果他們需要更多信息,他們可以訪問javadoc 。 誰知道,他們可能會喜歡它,並與Guava提供的所有其他優點一起開始使用它:-)

從問題陳述中(“一組給定的字符串應該只有一個類”),聽起來您真正想要的是Interner<ImmutableSet<String>>

  • Interner是一種實用程序(使用Interners.newStrongInterner()構造一個實用程序),用於確保您只有一個對象的任何實例以及任何給定的數據。
  • 如果您的集合是不可變的並且是按任意順序支持成員資格測試的集合,則ImmutableSet是正確的選擇。

或者,您可能希望查看Cache<ImmutableSet<String>> (有關詳細信息,請參見Caches Explained )。

我將使用Attempt #2不是Attempt #1 ,因為它記錄了您始終返回ImmutableList實例的情況。 通常,選擇盡可能具體的返回類型和盡可能一般的參數類型很有用。 但是對於這兩種情況,接口都比具體類更喜歡。

好吧, ImmutableList是一個抽象類,而不是一個接口。 但是由於其性質,它的行為非常像界面。

當您的類成員引用spellings在對象的生存spellings無法更改和/或您希望使整個類本身不可變時, Attempt #3有意義。 否則,當可以在對象生存期內將spellings分配給另一個ImmutableList時,則沒有意義。

考慮到您的示例中的用例,我傾向於說#3是最佳選擇。

暫無
暫無

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

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