ヌルオブジェクトパターン

ヌルオブジェクトパターン(Null Object Pattern)では、空のオブジェクトがNULLオブジェクトインスタンスのチェックに取って代わります。Nullオブジェクトは空の値をチェックするのではなく、何の動作も行わない関係を反映します。このようなNullオブジェクトは、データが利用できない場合にデフォルトの動作を提供することもできます。

ヌルオブジェクトパターンでは、実行するさまざまな操作を指定する抽象クラスと、そのクラスを拡張するエンティティクラスを作成し、また、そのクラスに対して何も実装しないヌルオブジェクトクラスを作成します。このヌルオブジェクトクラスは、空の値をチェックする必要がある場所でシームレスに使用されます。


概要

意図

null値の代わりに空のオブジェクトを使用します。この空のオブジェクトは同じインターフェースを実装しますが、リクエストに対して何も操作を行わないか、デフォルトの操作を提供します。

主な解決問題

  • ヌルオブジェクトパターンは、システムでnull値を使用することによって引き起こされる可能性がある問題(NullPointerException例外など)を解決します。
  • 適切なオブジェクトがない場合に、システムが失敗するのではなく、「安全な」空のオブジェクトを使用して実行を継続できるようにします。

使用シーン

  • システム内でnullオブジェクトを処理する必要があるが、nullチェックやnull値の処理を避けたい場合。

実装方法

  • プロトコルを定義する:プロトコルまたはインターフェースを定義し、実装する必要がある動作を規定します。
  • 具象オブジェクトを作成する:プロトコルを実装する具象オブジェクトであり、実際の動作を提供します。
  • 空のオブジェクトを作成する:同じプロトコルを実装しますが、「空」の実装を提供します。つまり、意味のある操作を一切実行しません。

重要なコード

  • プロトコルまたはインターフェース:オブジェクトが実装する必要があるメソッドを規定します。
  • 具象オブジェクト:プロトコルを実装し、実際のビジネスロジックを含みます。
  • 空のオブジェクト:プロトコルを実装しますが、メソッドの実装は空またはデフォルトの動作です。

応用例

  • ログシステム:ログシステムでは、空のオブジェクトは何も操作を実行しないロガーを表すことがあります。
  • デフォルトユーザー:システム内で現在ユーザーがいない場合、nullの代わりに空のユーザーオブジェクトを使用できます。

利点

  1. 空値チェックの回避:コード内のnull値チェックを排除します。
  2. クライアントコードの簡素化:クライアントはオブジェクトが空かどうかを気にせず、直接メソッドを呼び出すことができます。
  3. 拡張性:新しい具象オブジェクトの追加はクライアントに対して透過的であり、既存のコードを変更する必要はありません。

欠点

  • エラーを隠す可能性:空のオブジェクトを使用すると、エラーや異常状態が隠れてしまい、デバッグが困難になる可能性があります。
  • 設計の複雑さの増加:nullを返す可能性のあるすべてのインターフェースに対して、空のオブジェクトを実装する必要があります。

使用上のアドバイス

  • システム内でnull値を処理する必要があるが、エラー処理を簡素化し、nullチェックを避けたい場合は、ヌルオブジェクトパターンの使用を検討してください。

注意事項

  • ヌルオブジェクトパターンは慎重に使用する必要があります。エラーを隠したり、システムの実際の状態を隠したりしないようにしてください。
  • 空のオブジェクトは具象オブジェクトと同じインターフェースを提供し、クライアントコードを変更することなく使用できるようにする必要があります。

構造

ヌルオブジェクトパターンには、次の主要な役割が含まれます:

  • 抽象オブジェクト(Abstract Object):クライアントが期待するインターフェースを定義します。このインターフェースは抽象クラスまたはインターフェースにすることができます。

  • 具象オブジェクト(Concrete Object):抽象オブジェクトのインターフェースを実装する具象クラスです。これらのクラスは実際の動作を提供します。

  • 空のオブジェクト(Null Object):抽象オブジェクトのインターフェースを実装する空のオブジェクトクラスです。このクラスは、オブジェクトが利用できない場合に使用するためのデフォルトの無効な動作を提供します。具象オブジェクトの代替として、クライアントコードの空値チェックの代わりに使用できます。

実装

操作(ここでは顧客の名前)を定義するAbstractCustomer抽象クラスと、それを拡張したAbstractCustomerクラスのエンティティクラスを作成します。ファクトリークラスCustomerFactoryは顧客から渡された名前に基づいてRealCustomer 或 NullCustomerオブジェクトを返します。

NullPatternDemo、デモクラスはCustomerFactoryを使用してヌルオブジェクトパターンの使い方を示します。

空对象模式的 UML 图

ステップ 1

抽象クラスを作成します。

AbstractCustomer.java

public abstract class AbstractCustomer { protected String name; public abstract boolean isNil(); public abstract String getName(); }

ステップ 2

上記のクラスを拡張したエンティティクラスを作成します。

RealCustomer.java

public class RealCustomer extends AbstractCustomer { public RealCustomer(String name) { this.name = name; } @Override public String getName() { return name; } @Override public boolean isNil() { return false; } }

NullCustomer.java

public class NullCustomer extends AbstractCustomer { @Override public String getName() { return "Not Available in Customer Database"; } @Override public boolean isNil() { return true; } }

ステップ 3

作成CustomerFactoryクラス。

CustomerFactory.java

public class CustomerFactory { public static final String[] names = {"Rob", "Joe", "Julie"}; public static AbstractCustomer getCustomer(String name){ for (int i = 0; i < names.length; i++) { if (names[i].equalsIgnoreCase(name)){ return new RealCustomer(name); } } return new NullCustomer(); } }

ステップ 4

使用CustomerFactory、顧客から渡された名前に基づいて取得RealCustomer 或 NullCustomerオブジェクト。

NullPatternDemo.java

public class NullPatternDemo { public static void main(String[] args) { AbstractCustomer customer1 = CustomerFactory.getCustomer("Rob"); AbstractCustomer customer2 = CustomerFactory.getCustomer("Bob"); AbstractCustomer customer3 = CustomerFactory.getCustomer("Julie"); AbstractCustomer customer4 = CustomerFactory.getCustomer("Laura"); System.out.println("Customers"); System.out.println(customer1.getName()); System.out.println(customer2.getName()); System.out.println(customer3.getName()); System.out.println(customer4.getName()); } }

ステップ 5

プログラムを実行し、結果を出力します:

Customers
Rob
Not Available in Customer Database
Julie
Not Available in Customer Database
その他の拡張