Powered by SmartDoc

3 フィールド(属性/プロパティ)標準

この文書全体を通してフィールド(field)という用語を、属性(attribute)と示す語として使用する。Beans Development Kit(BDK)ではプロパティ(property)と呼ばれる(DeSoto,1997)。フィールドはオブジェクトまたはクラスを記述するデータの一部分である。フィールドは、stringやfloatといった基本型かもしくはcustomerとかbank accountのようなオブジェクトである。

3.1 フィールドの命名

3.1.1 フィールドの命名には完全な英語記述を使う

フィールドの命名には完全な英語の記述を使用(Gosling,Joy,Steele,1996; Ambler 1997)して、そのフィールドが表現していることが明確になるようにする。配列やベクタのような集合を表わすフィールドについては、複数の値があることを示す複数形の名前を与える。

リスト 3.1 例)
firstName, zipCode, unitPrice, discountRate, orderItems,sqlDatabase

フィールドの名前がsqlDatabaseのように頭字語(5)で始まるとき、頭字語(ここでは'sql')は全て小文字とすべきである。sQLDatabaseのような名前を使わない。

  1. 訳注:複数の語の頭文字を並べた語。ここではSQL。

3.1.1.1 別な命名-ハンガリアン記法

ハンガリアン記法(McConnell,1993)はフィールドを以下の方法で命名するという原理に基づいている。xEeeeeeEeeeee、xはコンポーネントの型を示し、EeeeeeEeeeeeは完全英語記述を示す。

リスト 3.2 例
sFirstName, iZipCode, lUnitPrice, lDiscountRate, cOrderItems

主な利点はこれがC++コードに関して工業規準共通になっており、多くの人が既にこれにしたがっている点である。さらに、開発者は変数の名前からその型とどのように使われるかを素早く判断できる。主な欠点は同じ型の属性をたくさん使うときに接頭詞の記法が負担になること、完全英語記述という命名規約を破ることになること、およびアクセッサ・メソッドの命名戦略に影響を及ぼすことである(3.4.1節参照)。

3.1.1.2 別な命名-先頭または末尾のアンダースコア

C++コミュニティから来た一般的なアプローチはフィールド名の先頭か末尾にアンダースコアを含めることである。

リスト 3.3 例
_firstName, firstName_

このアプローチの利点はフィールド名を扱っていることが一目で分かるため、パラメータやローカル変数によって隠蔽されることを防ぐことができる(繰り返しになるが、この場合の名前隠蔽はアクセッサ・メソッドを使用するなら問題にはならない)。主な欠点は、これがSunによる標準セットではないことである。

3.1.2 コンポーネント(ウィジェット)の命名

コンポーネント(インタフェースウィジェット)の命名には、ウィジェットの型を名前の後ろに付加した完全な英語記述を使用する(6)。コンポーネントの使用目的と型が名前を見ただけて分かるようになり、またコンポーネント一覧からどれか選びやすくする(多くのビジュアル開発環境ではアプレットやアプリケーションの中で使われるコンポーネントの一覧表示を提供しており、そこにbutton1, button2...と表示されていたなら混乱してしまう)。

リスト 3.4 例
okButton, customerList, fileMenu, newFileMenuItem
  1. これは私の規準であり、Sunが奨励しているものではない。

3.1.2.1 別なコンポーネント命名-ハンガリアン記法

リスト 3.5 例
pbOk, lbCustomer, mFile, miNewFile

利点は3.1.1.1節で述べられたものと同様である。主な欠点は同じ型のウィジェットをたくさん使うときに接頭詞の記法が負担になることである。

3.1.2.2 別なコンポーネント命名-接尾詞ハンガリアン記法

基本的には他の2つの案の組み合わせであり、okPb, customerLb, fileM, newFileMiのようになる。主な利点はコンポーネントの名前がウィジェットの型を示すことと同じ型のウィジェットがアルファベット順のリストで互いにグループ化されないことである。主な欠点は完全英語記述を使っていないので、規準から逸脱してしまい、規準を覚えるのが困難になることである。

Tip-コンポーネント名標準の設定

どの規約を選んだとしても、公式のウィジェット名一覧を必要とするだろう。例えば、ボタンを命名するときにButtonかPushButton、それともbかpbかを使いますか?リストを作成し、組織内のJava開発者に入手可能なようにする。

3.1.3 定数の命名

Javaでは定数は変更できない値であり、典型的にはクラスのstatic finalフィールドとして実装される。よく知られた規約としては、フルスペルの英単語を用い、すべて大文字で、単語間はアンダースコア'_'でつなぐ(Gosling,Joy,Steele,1996;Sandvik,1996;NPS,1996)。

リスト 3.6 例)
MINIMUM_BALANCE, MAX_VALUE, DEFAULT_START_TIME

この規約の主な利点は定数を変数と区別するのに役立つことである。この文書の後で触れるが、定数を定義するのではなく、定数の値を返却値として返すような読み出し(getter)メソッドを定義することで、コードの柔軟性と保守性を高めることができる。

3.1.4 集合(コレクション)の命名

配列、Vector、などの集合を表わすフィールドは、中にしまわれるオブジェクトの型を複数形にした名前を使用する。名前には、完全英語記述で、先頭の単語が小文字、先頭以外の各単語の頭は大文字を使用する。

リスト 3.7 例)
customers, orderItems, aliases

この規約の主な利点は単一の値を保持するフィールドと複数の値を保持する集合を表わすフィールドとを区別しやすい点にある。

3.1.4.1 別な集合の命名-'Some'アプローチ

標準ではないアプローチだが興味深いものとして、集合名の接頭詞に'some'を付けるものがある。

リスト 3.8 例
someCustomers, someOrderItems, someAliases

3.1.5 名前を隠蔽しない

名前隠蔽とは、ローカル変数、引数あるいはフィールドの命名において、それより大きなスコープの他の変数と同じ(または類似)名前を付けてしまうことを示す。例えば、firstNameというフィールドがある場合、ローカル変数やパラメータにfirstNameと名前を付けない。また、firstNamesやfistNameといった近い名前を付けない(もしかすると誰かが自分の拳(7)に名前を付けているかもしれない、僕自身は自分のには単に"右"と"左"と呼ぶけどね(笑))。他の開発者や自分自身も含めコードを修正しているときに誤読し、エラーを見つけるのが困難になるので、コードを理解するのが難しくバグを招きやすいこのような名前の隠蔽は避けること。

  1. 訳注:fistは拳の意味

3.2 フィールドの可視性

Visionチーム(1996)はカプセル化の理由からフィールドをpublicとして宣言しないよう提唱している。私はさらにフィールドはすべてprivateとして宣言するべきであると述べる。もしフィールドがprotectedとして宣言されていると、サブクラスのメソッドが直接そのフィールドにアクセスする可能性があり、クラス階層の間で結合度がかなり増加する。これはクラスの保守と拡張をより困難にしてしまうので、避けるべきである。フィールドは直接アクセスしてはならず、代わりにアクセッサ・メソッドを使うべきである。

可視性 内容 使用方法
public 他のどのクラス/オブジェクトに属するメソッドからでもアクセス可能 フィールドはpublicにしないこと
protected そのクラス自身のメソッドまたはサブクラスのメソッドからアクセス可能 フィールドはprotectedにしないこと
private そのクラス自身のメソッドからのみアクセス可能で、サブクラスからはアクセス不可能 フィールドはprivateとしgetterまたはsetterメソッドによってアクセスすること

フィールドが永続性を持たないときは、staticまたはtransient修飾子を付加する(DeSoto,1997)。これはBDKの規約に適合する。

3.3 フィールドのドキュメント

それぞれのフィールドには、他の開発者が理解できるに十分なドキュメントをコメントに記述すること。ドキュメントとして記述する内容は、

  1. それ自身の記述

    どのように使うか他の開発者に分かるように記述する。

  2. 適用できるすべての不変条件をドキュメントする

    フィールドの不変条件はそれについて常に真となる条件のことである。例えば、フィールドdayOfMonthについての不変条件はその値が1から31の間を取る(明らかにこの不変条件をより複雑して年と月に基づいたフィールド値となるように制約することもできる)。 フィールドの値の取りうる制約事項をドキュメントすることで、重要なビジネスルールを定義するのに役立ち、コードがどのように動作するか理解しやすくする。

  3. 使用例

    複雑なビジネスルールに関わるフィールドについては、それを理解容易にするために何通りかの使用例を提供する。この例は絵で書いてもよい。百聞は一見に如かずである。

  4. 並行性

    並行性は大部分の開発者にとっては新しくまた複雑な概念であり、並行プログラミングの経験を積んだプログラマーにとってもせいぜいなじみはあるが複雑な問題である。要するに、Javaの並行プログラミング特性を使用したならば、徹底的にドキュメントする必要があるということだ。

  5. 可視性の決定

    フィールドをprivate以外の可視性として宣言したならば、なぜそうしたかを必ずドキュメントする。フィールドの可視性については前に述べたとおりであり、アクセッサ・メソッドを使用してカプセル化を行うことについては後の章で述べる。要点は、private以外の宣言を行うならば、それを行うだけの十分な理由を持っていること。

3.4 アクセッサメソッドの使用

フィールドについての保守性にとって、フィールドの命名規約だけでなく適切なアクセッサメソッドの使用が不可欠である。アクセッサメソッドは、フィールドの値を更新したり読み出したりするためのメソッドのことである。アクセッサメソッドにはこの2つの目的によってsetter(mutatorとも呼ばれる)とgetterとに分類できる。setterは変数の値を変更し、getterは変数の値を取得する。

アクセッサ・メソッドを使用することでコードにオーバーヘッドが生じていたけれども、今日のJavaコンパイラはアクセッサ・メソッドの使用を最適化するので、もはや真ではない。アクセッサは、クラスの実装方法詳細を隠蔽する。変数にアクセスする個所を多くても2つ(setterとgetter)に制限することによって、コードを変更する時の影響範囲を極小化することができるため、保守性が向上する。Javaコードの最適化については7.3節で議論する。あなたの組織において実施できる重要な標準の一つがアクセッサの使用である。開発者の中には余計なタイプ量(例えばgetterの場合フィールド名が増えるだけでなくさらに'get'と'()'も)を嫌ってアクセッサ・メソッドを使いたがらない者がいるかもしれない。要点は、アクセッサを使うことで保守性と拡張性が増加するということである。

Tip-アクセッサはフィールドにアクセスする唯一の場所である

アクセッサ・メソッドを適切に使用する鍵となる概念は、フィールドを直接操作できるメソッドはアクセッサ・メソッド自身だけであるということである。確かにフィールドが定義されるクラスのメソッドからは、privateなフィールドであっても直接アクセス可能であるが、クラス内の結合度を増大させることになるのでそうしないこと。

3.4.1 アクセッサメソッドの命名

フィールドの値を取り出すGetterメソッドは、「'get'+フィールド名」と命名する。ただし、フィールドがbooleanを表現する場合は、「'is'+フィールド名」と命名する。フィールドの値を更新するSetterメソッドは、フィールドの型によらず「'set'+フィールド名」と命名する(Gosling,Joy,Steele,1996;DeSoto,1997)。フィールド名は大文字小文字混合で構成し、フィールド名を構成する各単語の最初の文字を大文字とする。この命名規約はJDKにおいて使われている方法とBean開発に要求されていることに一致している。

表 3.1 命名例
Field Type Getter名 Setter名
firstName String getFirstName() setFirstName()
address Object getAddress() setAddress()
persistent boolean isPersistent() setPersistent()
customerNumber int getCustomerNumber() setCustomerNumber()
orderItems Array of Object getOrderItems() setOrderItems()

3.4.2 アクセッサ・メソッドの応用技術

アクセッサを単にインスタンス・フィールドの値の読み出し・更新だけに使うだけでなく、コードの柔軟性を高めるより効果的な使用方法がある。

3.4.2.1 フィールドの怠惰な初期化(Lazy Initialization)

変数は使用される前に初期化されている必要がある。初期化の方法は2つの考え方があり、第一の考え方はオブジェクトが生成されるときに全変数を初期化するもの(traditional approach)、第二の考え方はオブジェクトが最初に使われるときになって変数を初期化するというもの。最初の方法はオブジェクトが最初に生成されるときに起動される特殊なメソッド、すなわちコンストラクタを使う。この方法ではエラーを招きやすいことがある。新たな変数を追加する作業時に、コンストラクタを更新することを忘れがちとなる。もう一つの方法はlazy initializationと呼ばれる、フィールドをGetterメソッドによって初期化するものである。下記コード参照(8)。メソッドがbranch numberがゼロかどうかチェックし、ゼロならば適切な初期値を設定する。

/**
  口座番号の左端4桁である支店コードを返却する。
  口座番号の書式は、BBBBAAAAAAA 
 */
protected int getBranchNumber() {
    if (branchNumber == 0) {
        // デフォルトの支店コードは1000である。
        // これはベドロック市にある本店の支店番号である。
	setBranchNumber(1000);
    }
    return branchNumber;
}

この怠惰な初期化は、フィールドをデータベースに格納しているオブジェクトの場合などでは非常によく使われる方法である。例えば、新しい在庫品を生成するとき、デフォルトとして設定した在庫品型をデータベースから取り出す必要はない。代わりにlazy initializationを使って、最初にアクセスされたときにその値を設定し、必要なときだけデータベースから在庫品型を取り出す。この方法は、頻繁にアクセスされないフィールドを持つオブジェクトに利点をもたらす。使わないのに永続ストレージから何かを引き出すオーバーヘッドを招くのでしょうか?怠惰な初期化をgetterメソッドで使うときは必ずデフォルト値は何なのか、上述コード例で見たようにドキュメントする。ドキュメントすることでコード中のフィールドがどのように使われているかという疑問を払拭し、保守性と拡張性の両方を高める。

  1. 注:getterメソッドの中でsetterメソッドが使われる方法

3.4.2.2 定数へのアクセス

一般的なJavaの知恵(多分知恵というのは誤った用語だろう)では、定数をstatic finalなフィールドとして実装する。この方法は「定数」が安定していると保証されている場合に限り意味をなす。例えば、Booleanクラスは2つのstatic finalフィールドでそのクラス自身のインスタンスでもあるTRUEとFALSEを実装する。また、DAYS_IN_A_WEEK定数の値もおそらく決して変更されない(9)ため意味をなす。

しかしながら、ビジネスに関する定数はビジネスルールの変更によって何度も変更されうる。以下に例を考えてみる。Archon Bank of Cardassia(ABC)では利息を得るには口座に少なくても$500以上の残高がなくてはならない。この実装として、AccountクラスにstaticなフィールドMINIMUM_BALANCEを追加し、利息を計算するメソッドの中で使うやり方がある。この実装は動作はするが柔軟性がない。ビジネスルールが変更され、別な種類の口座には別な最低残高が適用され、例えば普通預金口座では$500だが当座預金口座では$200となった場合はどうなるのだろうか?また、ビジネスルールが変更され、初年度が最低残高$500、2年目には$400、3年目には$300、・・・となったらどうだろう?夏場は$500で冬場は$250となる場合はどうだろう?(10)最後にはこれらルールのすべてを実装するはめになるだろう。

定数をフィールドとして実装することは柔軟性を欠くということがポイントである。よりよい解決法は、定数をGetterメソッドとして実装することである。上述の例では、static(クラス)メソッドgetMinimumBalance()がstaticフィールドMINIMUM_BALANCEよりもはるかにずっと柔軟である。なぜならば、様々なビジネスルールをメソッドに実装したり様々な種類の口座を適切にサブクラス化することができるからである。

/**
  口座番号の値を取得する。口座番号は次の書式である。
  BBBBAAAAAA
  ここで BBBB は支店番号を示し、AAAAAA は支店口座番号を示す。
 */
public long getAccountNumber() {
    return ((getBranchNumber() * 100000) + getBranchAccountNumber());
}

/**
  口座番号を設定する。口座番号は次の書式である。
  BBBBAAAAAA
  ここで BBBB は支店番号を示し、AAAAAA は支店口座番号を示す。
 */
public void setAccountNumber(int newNumber) {
    setBranchAccountNumber(newNumber % 1000000);
    setBranchNumber(newNumber / 1000000);
}

さらなる定数のgetterを使う利点は、コードの一貫性を向上させるのに役立つことである。上述のコードを考えてみると、正しく動作しないことが分かる。口座番号(account number)は支店番号(branch number)と支店口座番号(branch account number)とを結合したものである。このコードを試験すると、setterメソッドsetAccountNumber()が支店口座番号を正しく更新しないことが分かった(左4桁を取り除かず左3桁を取り除いていた)。それは、branchAccountNumberを取り出すのに100,000ではなく1,000,000を使っていたからである。この値について単一のソースコードとして以下に示すように定数のgetterメソッドgetAccountNumberDivisor()を適用したら、コードはより一貫性が向上し、正しく動作するだろう。

/**
  口座番号に含まれる支店番号と支店口座番号を分離するための
  除数値を返却する。
  口座番号の書式は、BBBBAAAAAAである。
*/
public long getAccountNumberDivisor() {
    return ((long)1000000);
}

/**
  口座番号を返却する。口座番号は次の書式である。
  BBBBAAAAAA
  ここで BBBB は支店番号を示し、AAAAAA は支店口座番号を示す。
 */
public long getAccountNumber() {
    return ((getBranchNumber() * getAccountNumberDivisor()) + 
                                     getBranchAccountNumber());
}

/**
  口座番号を設定する。口座番号は次の書式である。
  BBBBAAAAAA
  ここで BBBB は支店番号を示し、AAAAAA は支店口座番号を示す。
 */
public void setAccountNumber(int newNumber) {
    setBranchAccountNumber(newNumber % getAccountNumberDivisor());
    setBranchNumber(newNumber / getAccountNumberDivisor());
}

定数に関してアクセッサを使うことによってバグの可能性を低減し、同時にシステムの保守性を高める。口座番号の割付が変更になり、それを結果として知ることになったとしても(ユーザとはそうしたものである)、既に口座番号の構築・分解に必要な情報の隠蔽化と局所化を行っているのでコードは容易に変更することができる。

  1. 私はどの文化も一週は7日間であると仮定しているが確かかは分からない。十分多くの国際化アプリケーションの開発に巻き込まれてきた結果、この仮定が本当に正しいかは検証が必要であることを知った。
  2. やあ、私はカナダ人だ。実際起きたんだよ。

3.4.2.3 集合へのアクセス

アクセッサ・メソッドの主な目的は、フィールドへのアクセスを隠蔽してコードの結合を弱めることにある。配列やVectorのような集合は単純な値のフィールドに比べて複雑なため、普通のGetter/Setterメソッドよりも多くの処理を行う必要がある。典型的な操作としては、集合には要素の追加や削除があるので、アクセッサ・メソッドにもそのような操作が必要となる。私が使うアプローチは集合のフィールドについて以下のアクセッサ・メソッドを追加する。

メソッド種類 命名規約
集合自体のGetter getCollection()(12) getOrderItems()
集合自体のSetter setCollection() setOrderItems()
集合へオブジェクトを追加 insertObject() insertOrderItem()
集合からオブジェクトを削除 deletetObject() deleteOrderItem()
新しいオブジェクトを作成して集合へ追加 newObject() newOrderItem()

このアプローチの利点は集合が完全にカプセル化されており、後に別な構造に置き換えること(例えばlinked listとかB-treeに)ができることにある。

  1. 集合の命名規約は集合が包含する情報の型の複数形バージョンを使うことを思い出してくれ。ゆえにorder itemオブジェクトの集合はorderItemsと呼ばれる

3.4.2.4 複数のフィールドへの連続アクセス

アクセッサ・メソッドの強力な利点の1つに、ビジネスルールを効果的に(強制的に)使わせる点がある。 例としてShapeクラスの階層を考えると、Shapeのサブクラスは自身の位置を2つのフィールド:xPosition, yPositionを通じて知り、2次元平面をmove(Float xMovement, Float yMovement)メソッドを起動することで移動する。 この移動は、x軸、y軸両方を同時に(連続して)変更しなければ意味をなさない。(どちらかの引数に0.0を与えることは許容できる) したがって、moveメソッドはpublicとし、setXPosition、setYpositoinメソッドはprivateとし、moveメソッド内から適切に呼ばれるようにする。

別な実装として、以下に示すように両方のフィールドを一度に更新するsetterメソッドを紹介する。メソッドsetXPosition()とsetYPosition()はprivateのままで外部クラスやサブクラスから直接呼ばれることはない(以下のコードに直接呼ばれることはないことをドキュメントしておいてもよい)。

/**
 図形の位置を設定する
 */
protected void setPosition(Float x, Float y) {
    setXPosition(x);
    setYPosition(y);
}

/**
 X座標を設定する。
 重要:本メソッドではなくsetPosition()メソッドを呼ぶこと
 */
private void setXPosition(Float x) {
    xPosition = x;
}
/**
 Y座標を設定する。
 重要:本メソッドではなくsetPosition()メソッドを呼ぶこと
 */
private void setYPosition(Float y) {
    yPosition = y;
}

あら捜しのための注:この例をPointクラスの単一のインスタンスによって実装することもできたのだが、これは簡単な例題として実装しているのである。

3.4.3 アクセッサの可視性

常にprotectedにするよう努力すること。そうすれば、サブクラスだけがフィールドにアクセスできる。外部のクラスがフィールドにアクセスする必要が生じた場合にのみ、対応するGetter、Setterメソッドをpublicにする。よく使う手に、Getterメソッドをpublicとし、Setterメソッドをprotectedにするものがある。

不変性を保証するために、Setterメソッドをprivateにする必要が生じる場合がある。例えば、OrderクラスがOrderItemインスタンスの集合をフィールドを持っており、さらにorder全体の合計を示すorderTotalフィールドを持つと考える。このとき、orderTotalフィールドを変更するメソッドは、oerderItemの集合を操作するメソッドに限定するべきである。これらメソッドがOrderクラスに実装されているとすると、setOrderTotal()メソッドはprivateとするべきである。(getOrderTotal()メソッドはpublicにすることが多いかもしれない)

3.4.4 アクセッサを使う理由

「よいプログラムの設計はプログラムの各部分を、不必要な、意図しない、その他望ましくない外部の影響から隔離しようと試みるものである。したがって、アクセス制限が言語によって明示的かつチェック可能な手段として提供されねばならない。」(Kanerva,1997)アクセッサメソッドは以下の方法でクラスの保守性を向上する。

  1. フィールドの更新

    各フィールドを更新するのは単一個所に限定し、修正・試験を容易にする。すなわち、フィールドをカプセル化する。

  2. フィールドの値を取得

    フィールドが誰からどのようにアクセスされるかを完全に制御する。

  3. 定数の値とクラスの名前を取得

    定数値、クラス名をGetterメソッド内にカプセル化し、値・名前を変更する際にGetter内部だけを変更すればよいようにする。決して定数・名前を使用している全ての行を変更しなければならないような羽目に陥らないこと。

  4. フィールドの初期化

    怠惰な初期化(lazy initialization)を使ってフィールドが使用されるときには常に初期化済みであり、かつ必要なときにだけ初期化されることを保証する。

  5. サブクラスとスーパークラスの間の結合を疎にする

    サブクラスがスーパークラスから継承したフィールドにアクセスする時は必ず対応するアクセッサメソッドを介する。これによって、スーパークラスでフィールドの実装を変更してもサブクラスには影響を及ぼさず、効果的に結合を疎にすることができる。アクセッサによってスーパークラスの変更がサブクラスに波及する、いわゆる「もろい基盤クラス問題(fragile base class problem)」のリスクを低減する。

  6. 複数フィールドへの変更をカプセル化

    複数のフィールドに関係するビジネスルールを変更するとき、変更前と同じ機能を提供するようにアクセッサを修正することで新しいルールに対応できるようにする。

  7. 並行性を単純化

    Lea氏(1997)が指摘するように、フィールドの値に基づいてwaitをかける場合、SetterメソッドによってnotifyAllを通知する場面を単一個所に限定する。これによって、並行問題の記述を簡易にする。

  8. 名前の隠蔽問題をなくす

    ローカル変数とフィールドと同じ名前を適用しないように注意すべきだが、フィールドへのアクセスをすべてアクセッサ経由にすることで、直接操作することがなくなるため名前の隠蔽を気にすることなくローカル変数を自由に命名できるようになる。

3.4.5 アクセッサを使わない理由

実行時間が極度に重要な場合にはアクセッサを使いたくないかもしれないが、アプリケーション内の結合度が密になることを正当化できるほどの理由はほとんどない。連携する複数のフィールドの値を一貫させる場合、単一のフィールドのアクセッサを提供することはよくないという指摘(Doug Lea,1996)がなされ、まさにそのとおりであるが、全てのアクセッサをpublicにする必要はないという点を忘れている。他のフィールドの値と密接に関わるときは、一貫する正しいメソッドを提供し、アクセッサメソッドをprotectedやprivateにすればよい。すべてのアクセッサをpublicにする必要はない。

3.5 静的フィールドは常に初期化する

Doug Lea(1996)による指摘:静的フィールド(クラスフィールド)は、そのクラスのインスタンスが作られる前にアクセスされる可能性があるため、妥当な値を持つことを保証しなければならない。これには、static initializer(static{...}ブロック)を使えば(Grand,1997)クラスがロードされた時点で自動的に実行される。

これは、静的フィールドにアクセッサを使用しない場合にのみ生じる問題である。アクセッサメソッドを使うことにより、lazy initializationによってフィールドに常に値が設定されていることを保証できる。フィールドをカプセル化するアクセッサメソッドの使用により、フィールドがどのように使用されるかを完全に制御でき、コード内の結合を疎にすることができる。