今まで、一般的なプログラムでは、データなどが存在しない場合ヌルや数字のゼロを 利用して定義していました。例えば以下のサンプルでは、オブジェクトをnewで生成する時を 「車が存在する状態」としています。nullを値として渡した時は「車が存在しない状態」 としています。
車が存在する状態
Object car = new Car();
車が存在しない状態
car = null;
abstract public class BaseCar {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
abstract void drive();
}
public class Car extends BaseCar {
public Car() {}
void drive() {
System.out.println("ドライブする");
}
}
このメリットは単純に理解しやすいというのがあります。しかし存在するかしないかの 判定をロジック内に組み込む必要が出てきます。以下が簡単な分岐処理です。
一般にListや配列からオブジェクトを取り出して、そのオブジェクトに対して操作をする 事が結構あります。
public class TestMain {
public static void main(String [] args) {
// 配列に格納.
BaseCar [] cars = {
new Car(),
null
};
// null判定が必要.
for( BaseCar tmpCar : cars) {
if (tmpCar != null) {
tmpCar.drive();
}
}
}
}
オブジェクト指向では、「存在しない状態」をnullを使うのではなく空のオブジェクトは 「存在しない状態」として扱う実装方法も可能です。この方法のメリットとしては、空オブジェクト 自体は存在しているためポリモーフィズムの実現などが可能になります。例えば継承のクラス関係 で、空オブジェクトには、ダミーのメソッドをオーバーライドさせるなどがあります。
public class CarNothing extends BaseCar {
public CarNothing() {}
void drive() {
// ダミーのメソッドにしておく.
}
}
これによりif文やcase文がなくなります。
public class TestMain {
public static void main(String [] args) {
// 配列に格納.
BaseCar [] cars = {
new Car(),
new CarNothing()
};
// null判定が必要なし.
for( BaseCar tmpCar : cars) {
tmpCar.drive();
}
}
}
NullObjectパターンは、複雑な状態管理などがある場合Stateパターンと併用して使われたりします。 Webアプリケーションなどでは状態管理を意識しなければいけないので便利に使える場合があります。 また分岐処理が複雑になりすぎた場合などのリファクタリングとして使われる場合もあるようです。