
Null Object Pattern(ヌルオブジェクトパターン)は、「nullチェックを無くしてコードをシンプルにする」ためのデザインパターン。
多くのコードで、こんな書き方をしていないでしょうか?
if (user != null) {
user.sendMail();
}
「nullの時に何もしない、またはエラーを避けるため」に条件分岐を書いているであろう、このようなコードが、あちこちに散らばると、
煩雑で保守しづらいコードになります。
※単に値がないだけであれば、nullでいいのだが、何もしない処理の判定でnullを使うと、意味合いが変わっている可能性が高いですからね。
Null Object Patternでは、「何もしないオブジェクト」を用意するパターンになります。
それをnullの代わりに返すことで、呼び出し側は常に同じインターフェースを使えるようにするのが目的です。
構造
1. Interface(共通インターフェース)
実オブジェクトとヌルオブジェクトで共通のメソッドを定義
2. Real Object(実装)
通常のロジックを実行
3. Null Object(空の実装)
何もしない、エラーを起こさない
4. Client(利用側)
nullチェック不要で呼び出せる
よく使われる場面
・ログ出力(NullLogger)
・キャッシュ(NullCache)
・認証ユーザー(AnonymousUser)
・外部API連携(NullServiceClient)
サンプルコード
// 共通インターフェース
class User {
sendMail() {}
}
// 実オブジェクト
class RealUser extends User {
constructor(email) {
super();
this.email = email;
}
sendMail() {
console.log(`メールを送信しました: ${this.email}`);
}
}
// Nullオブジェクト
class NullUser extends User {
sendMail() {
// 何もしない
console.log("NullUser: メール送信スキップ");
}
}
// Factory的な取得処理
function getUser(email) {
return email ? new RealUser(email) : new NullUser();
}
// === 利用側 ===
const users = [getUser("test@example.com"), getUser(null)];
users.forEach(u => u.sendMail());
実行結果
メールを送信しました: test@example.com
NullUser: メール送信スキップ
メリット
・nullチェック不要(if (user != null)が不要)
・クライアントコードが単純化
・オブジェクト指向の一貫性が保てる(ポリモーフィズム)
デメリット
・「何もしない動作」が隠蔽され、バグに気づきにくい場合がある
・状況によっては「明示的なnullチェック」のほうが安全
Null乱用の危険性について
Nullは、「何もしない」ではなく「存在しない」というのが本来の意味です。
「値が存在しない」という意味しか持たない。ので、冒頭のコードは、userというclassオブジェクトが存在しないという意味での判定に捉えられてしまいます。
このコードのままだったら、もしかしたらインスタンス定義がされていないのか?、それとも本来何かしらの値が入っているべきでそれが入っていないことを表しているのかが不明になる可能性があります。
色々な用途で使われた時に、null値は、次のような判定で使われる場合が多いようです。
・データが存在しない?
・ロード中?
・エラーが起きた?(処理や値が存在しない?)
・アクセス権がない?
これらを null という値だけで判定したコードを書いてしまうと、そのコード自体が意味が分かりにくいコードになってしまう可能性が高いです。
それを回避するために、Null Object Pattern が、「ポリモーフィズムによる明示的な安全策」として存在します。
比較
| 比較項目 |
null |
Null Object |
| 意味 |
存在しない |
何もしない |
| 安全性 |
呼び出すと例外 |
例外にならない |
| 呼び出し側 |
nullチェック必要 |
不要 |
| 戻り値の型 |
不定(null混在) |
一貫(常に同型) |
| 意図の明確さ |
曖昧 |
明示的(NullUserなど) |
あとがき
nullと、falseと、undefined、Nan、0...といった、Not系の値っていくつかありますが、
それぞれ適正に使われていないと、可読性が低いコードになってしまいます。
そんな時に、こうしたNot系の値に依存せずに、個別に細かな意味合いでの判定に使えるのが、今回の Null Object Pattern なんですね。
今回の説明を見ると、Nullを使うのが怖くなってしまうかもしれませんが、値が存在しない(変数に値が無い)という状態判定の時には、存分にNullを使っちゃってください。
そして、Null Object を使い慣れると、もはやnullを使わないコードを書くようになるかもしれませんけどね。
0 件のコメント:
コメントを投稿