PHPマスター| The Null Object Pattern - Polymorphism in Domain Models
コアポイント
- 空のオブジェクトパターンは、多型を使用して条件付きコードを削減し、コードをより簡潔でメンテナンスにしやすくするデザインパターンです。実際のオブジェクトを置き換えることができる非機能的オブジェクトを提供し、ヌル値チェックの必要性を排除します。
- 空のオブジェクトモードは、ファクトリーモードの作成と戻りのファクトリーモードや、実行時にオブジェクトの動作を変更するポリシーモードなど、他の設計モードと組み合わせて使用できます。
- 空のオブジェクトパターンの潜在的な欠点は、不要なオブジェクトの作成につながり、メモリの使用量を増やす可能性があることです。また、追加のクラスとインターフェイスが必要であるため、コードをより複雑にする場合があります。
- 空のオブジェクトパターンを実装するには、実際のオブジェクトと同じインターフェイスを実装する空のオブジェクトクラスを作成する必要があります。この空のオブジェクトは、インターフェイス内のすべてのメソッドのデフォルトの実装を提供し、実際のオブジェクトを置き換えることができます。これにより、コードがより堅牢でエラーが発生しやすくなります。
仕様に完全に準拠していませんが、直交性は「優れたデザイン」の原則に基づいたソフトウェアシステムの本質であり、モジュールが互いに分離され、システムが少なくなると言えます。硬くて脆弱な問題が発生しやすい。もちろん、実際にこのプロセスを実行するよりも、直交システムの利点について話す方が簡単です。それでも、システム内で高度に分離されたコンポーネントを達成することは決してユートピアの概念ではありません。多型などのさまざまなプログラミングの概念により、柔軟なプログラムの設計により、その部分は実行時に切り替えることができ、その依存関係は具体的な実装ではなく抽象的な形式で表現できます。 「インターフェイス指向プログラミング」の古いモットーは、インフラストラクチャまたはアプリケーションロジックを実装しているかどうかにかかわらず、時間とともに広く採用されてきたと思います。ただし、ドメインモデルの領域に足を踏み入れると、状況は非常に異なります。率直に言って、これは予測可能なシナリオです。結局のところ、相互に関連したオブジェクトのネットワーク(明確に定義されたビジネスルールによって制限されているデータと動作を持つ)は、なぜ多型である必要があるのでしょうか?それ自体はあまり意味がありません。ただし、この規則にはいくつかの例外があり、最終的にはこの状況に適用される可能性があります。最初の例外は、仮想プロキシの使用です。これは、実際のドメインオブジェクト実装と同じインターフェイスです。別の例外は、いわゆる「ヌルケース」です。これは、操作が十分に満たされたエンティティを埋める代わりにnull値を割り当てるか、戻ることになる可能性がある特別なケースです。従来の非政治的アプローチでは、モデルのユーザーはこれらの「有害な」ヌル値をチェックし、条件を優雅に処理し、コード全体に条件付きステートメントが爆発する必要があります。幸いなことに、この一見紛らわしい状況は、問題のオブジェクトと同じインターフェイスを実装するドメインオブジェクトのマルチブランチ実装を作成するだけで簡単に解決できます。操作の実行中にugいnull値を繰り返し確認します。当然のことながら、このアプローチは、多型の利点を極端にもたらす空のオブジェクトと呼ばれる設計パターンです。この記事では、いくつかのケースでこのパターンの利点を示し、それらがどのように多型の方法に密接に結びついているかを示します。
非政治的条件を扱う
予想されるように、空のオブジェクトパターンの利点を示すときに試す方法はいくつかあります。私が見つけた特に簡単なアプローチは、汎用ファインダーからnull値を返すことになる可能性のあるデータマッパーを実装することです。 1つのユーザーエンティティのみで構成されるスケルトンドメインモデルを正常に作成したとします。インターフェイスとそのクラスは次のとおりです
<?php namespace Model; interface UserInterface { public function setId($id); public function getId(); public function setName($name); public function getName(); public function setEmail($email); public function getEmail(); }
<?php namespace Model; class User implements UserInterface { private $id; private $name; private $email; public function __construct($name, $email) { $this->setName($name); $this->setEmail($email); } public function setId($id) { if ($this->id !== null) { throw new BadMethodCallException( "The ID for this user has been set already."); } if (!is_int($id) || $id throw new InvalidArgumentException( "The ID for this user is invalid."); } $this->id = $id; return $this; } public function getId() { return $this->id; } public function setName($name) { if (strlen($name) 30) { throw new InvalidArgumentException( "The user name is invalid."); } $this->name = $name; return $this; } public function getName() { return $this->name; } public function setEmail($email) { if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { throw new InvalidArgumentException( "The user email is invalid."); } $this->email = $email; return $this; } public function getEmail() { return $this->email; } }
<?php namespace ModelMapper; use LibraryDatabaseDatabaseAdapterInterface, ModelUser; class UserMapper implements UserMapperInterface { private $adapter; public function __construct(DatabaseAdapterInterface $adapter) { $this->adapter = $adapter; } public function fetchById($id) { $this->adapter->select("users", array("id" => $id)); if (!$row = $this->adapter->fetch()) { return null; } return $this->createUser($row); } private function createUser(array $row) { $user = new User($row["name"], $row["email"]); $user->setId($row["id"]); return $user; } }
<?php use LibraryLoaderAutoloader, LibraryDatabasePdoAdapter, ModelMapperUserMapper; require_once __DIR__ . "/Library/Loader/Autoloader.php"; $autoloader = new Autoloader; $autoloader->register(); $adapter = new PdoAdapter("mysql:dbname=test", "myusername", "mypassword"); $userMapper = new UserMapper($adapter); $user = $userMapper->fetchById(1); if ($user !== null) { echo $user->getName() . " " . $user->getEmail(); }
クライアントコードから条件ステートメントを削除します
しかし、これは、空のオブジェクトパターンが多型が神の恵みである理由を示す場合に正確にあるため、心配する必要はありません。これらの迷惑な条件付きステートメントを完全に取り除きたい場合は、以前のユーザークラスの多型バージョンを実装できます。
<?php namespace Model; class NullUser implements UserInterface { public function setId($id) { } public function getId() { } public function setName($name) { } public function getName() { } public function setEmail($email) { } public function getEmail() { } }
MapperのcreateUser()メソッドは、Finderに渡されたIDが有効なユーザーを返さないときに空のユーザーを作成する責任があるため、小さな状態を隠します。それでも、この微妙なコストは、クライアントコードの作業を多くの繰り返しチェックを行うだけでなく、空のユーザーに対処しなければならないときに文句を言うことのないゆるい消費者にも変えます。
<?php namespace ModelMapper; use LibraryDatabaseDatabaseAdapterInterface, ModelUser, ModelNullUser; class UserMapper implements UserMapperInterface { private $adapter; public function __construct(DatabaseAdapterInterface $adapter) { $this->adapter = $adapter; } public function fetchById($id) { $this->adapter->select("users", array("id" => $id)); return $this->createUser($this->adapter->fetch()); } private function createUser($row) { if (!$row) { return new NullUser; } $user = new User($row["name"], $row["email"]); $user->setId($row["id"]); return $user; } }
<?php namespace Model; interface UserInterface { public function setId($id); public function getId(); public function setName($name); public function getName(); public function setEmail($email); public function getEmail(); }
この多型アプローチの主な欠点は、無効なエンティティを扱うときにクラッシュしないため、使用するアプリケーションが緩すぎることです。最悪の場合、ユーザーインターフェイスにはいくつかの空白の行のみが表示されますが、本当にうるさいものは私たちをうんざりさせるものはありません。これは、初期のヌルーザークラスの現在の実装をスキャンするときに特に明白です。それが実現可能であっても、推奨されるものは言うまでもなく、その多型を変更せずに空のオブジェクトのロジックをカプセル化することもできます。空のオブジェクトは、いくつかの特別なケースでのみクライアントコードにさらされるべきデフォルトデータと動作をカプセル化するのに最適であるとさえ言えます。あなたが十分に野心的で、シンプルな空のユーザーオブジェクトでこのコンセプトを試したい場合、現在のNulluserクラスは次のようにリファクタリングできます:
<?php namespace Model; class User implements UserInterface { private $id; private $name; private $email; public function __construct($name, $email) { $this->setName($name); $this->setEmail($email); } public function setId($id) { if ($this->id !== null) { throw new BadMethodCallException( "The ID for this user has been set already."); } if (!is_int($id) || $id throw new InvalidArgumentException( "The ID for this user is invalid."); } $this->id = $id; return $this; } public function getId() { return $this->id; } public function setName($name) { if (strlen($name) 30) { throw new InvalidArgumentException( "The user name is invalid."); } $this->name = $name; return $this; } public function getName() { return $this->name; } public function setEmail($email) { if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { throw new InvalidArgumentException( "The user email is invalid."); } $this->email = $email; return $this; } public function getEmail() { return $this->email; } }
nulluserの拡張バージョンは、静かな前任者よりもわずかに表現力があります。ゲッターは、無効なユーザーを要求するときにいくつかのデフォルトメッセージを返すための基本的な実装を提供するためです。些細なことですが、この変更は、クライアントコードが空のユーザーを処理する方法にプラスの影響を与えます。今回は、少なくとも存在しないユーザーをストレージから抽出しようとすると問題が発生することを少なくとも知っているからです。これは良いブレークスルーであり、実際には空ではない空のオブジェクトを実装する方法を示すだけでなく、特定のニーズに基づいて関連するオブジェクト内でロジックを移動するのがどれほど簡単かを示します。
結論
空のオブジェクトを実装することは、特にPHPではOOP(多型など)のコア概念が大幅に過小評価されていることが厄介であると言う人もいるかもしれません。彼らはある程度正しいです。それにもかかわらず、信頼できるプログラミングの原則と設計パターンの徐々に採用されたもの、言語オブジェクトモデルが到達した成熟度のレベルは、着実に前進し、複雑で非現実的な概念と見なされた「高級品」の一部を使用し始めることです。少し前に必要なすべての根拠を提供します。 nullオブジェクトパターンはこのカテゴリに分類されますが、その実装は非常にシンプルでエレガントであるため、クライアントコードで重複したnullチェックをクリアするときに魅力的ではないことは困難です。 Fotoliaの写真
(スペースの制限のため、元のテキストのFAQ部分はここで省略されています。)以上がPHPマスター| The Null Object Pattern - Polymorphism in Domain Modelsの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











PHPでは、Password_hashとpassword_verify関数を使用して安全なパスワードハッシュを実装する必要があり、MD5またはSHA1を使用しないでください。 1)password_hashセキュリティを強化するために、塩値を含むハッシュを生成します。 2)password_verifyハッシュ値を比較して、パスワードを確認し、セキュリティを確保します。 3)MD5とSHA1は脆弱であり、塩の値が不足しており、最新のパスワードセキュリティには適していません。

PHPとPythonにはそれぞれ独自の利点があり、プロジェクトの要件に従って選択します。 1.PHPは、特にWebサイトの迅速な開発とメンテナンスに適しています。 2。Pythonは、データサイエンス、機械学習、人工知能に適しており、簡潔な構文を備えており、初心者に適しています。

PHPは、電子商取引、コンテンツ管理システム、API開発で広く使用されています。 1)eコマース:ショッピングカート機能と支払い処理に使用。 2)コンテンツ管理システム:動的コンテンツの生成とユーザー管理に使用されます。 3)API開発:RESTFUL API開発とAPIセキュリティに使用されます。パフォーマンスの最適化とベストプラクティスを通じて、PHPアプリケーションの効率と保守性が向上します。

PHPタイプは、コードの品質と読みやすさを向上させるためのプロンプトがあります。 1)スカラータイプのヒント:php7.0であるため、基本データ型は、int、floatなどの関数パラメーターで指定できます。 3)ユニオンタイプのプロンプト:PHP8.0であるため、関数パラメーターまたは戻り値で複数のタイプを指定することができます。 4)Nullable Typeプロンプト:null値を含めることができ、null値を返す可能性のある機能を処理できます。

PHPは依然として動的であり、現代のプログラミングの分野で重要な位置を占めています。 1)PHPのシンプルさと強力なコミュニティサポートにより、Web開発で広く使用されています。 2)その柔軟性と安定性により、Webフォーム、データベース操作、ファイル処理の処理において顕著になります。 3)PHPは、初心者や経験豊富な開発者に適した、常に進化し、最適化しています。

PHPは主に手順プログラミングですが、オブジェクト指向プログラミング(OOP)もサポートしています。 Pythonは、OOP、機能、手続き上のプログラミングなど、さまざまなパラダイムをサポートしています。 PHPはWeb開発に適しており、Pythonはデータ分析や機械学習などのさまざまなアプリケーションに適しています。

PHPとPythonには独自の利点と短所があり、選択はプロジェクトのニーズと個人的な好みに依存します。 1.PHPは、大規模なWebアプリケーションの迅速な開発とメンテナンスに適しています。 2。Pythonは、データサイエンスと機械学習の分野を支配しています。

PHPで前処理ステートメントとPDOを使用すると、SQL注入攻撃を効果的に防ぐことができます。 1)PDOを使用してデータベースに接続し、エラーモードを設定します。 2)準備方法を使用して前処理ステートメントを作成し、プレースホルダーを使用してデータを渡し、メソッドを実行します。 3)結果のクエリを処理し、コードのセキュリティとパフォーマンスを確保します。
