オブジェクトが何らかの形で変更された場合、そのオブジェクトを使用するすべてのコードも同様に変更する必要があります。たとえば、人の名、姓、およびその他の名前が PersonName オブジェクトにカプセル化されている場合、変更に対応するためにすべてのコードを変更する必要があります。
良い OO 習慣 (リスト 2 を参照) を使用することにより、同じオブジェクトにパブリック フィールドの代わりにプライベート フィールドが設定され、アクセス メソッドと呼ばれる get メソッドと set パブリック メソッドを通じて慎重に外部に公開されます。プライベートフィールド。これらのアクセス メソッドは、PHP クラスから情報を取得するためのパブリックな方法を提供するため、実装が変更された場合でも、そのクラスを使用するすべてのコードを変更する必要が少なくなる可能性があります。
リスト 2. パブリック アクセス メソッドを使用する良い習慣
public function getGivenName()
{
return $this->personName'
}
/ * etc... */
}
/*
* 内部実装は変更されましたが、ここのコードは
* そのままであり、変更は
*/
$person にのみカプセル化されています。 = 新しい人();
$人->setPrefix("ジョン");
echo($人->getPrefix()); person- >getGivenName());
?>
良き隣人になりましょう
クラスを構築するときは、クラス自体のエラーを正しく処理する必要があります。クラスがエラーの処理方法を知らない場合は、呼び出し元が理解できる形式でエラーをカプセル化する必要があります。さらに、空のオブジェクトや無効な状態のオブジェクトを返すことは避けてください。多くの場合、これはパラメータを検証し、指定されたパラメータが無効である理由を説明する特定の例外をスローするだけで実現できます。この習慣を身につければ、あなただけでなく、コードを保守したりオブジェクトを使用したりする人々も、多くの時間を節約できます。
悪い習慣: エラーを処理しない
リスト 4 に示す例を考えてみましょう。この例では、いくつかのパラメーターを受け取り、いくつかの値が入った Person オブジェクトが返されます。ただし、parsePersonName() メソッドでは、指定された $val 変数が空であること、長さ 0 の文字列であること、または文字列が解析不可能な形式であることは検証されません。 parsePersonName() メソッドは Person オブジェクトを返さず、null を返します。このアプローチを使用する管理者やプログラマーは、それが面倒だと感じるかもしれません。少なくとも、今すぐブレークポイントの設定と PHP スクリプトのデバッグを開始する必要があります。
リスト 4. エラーをスローまたは処理しない悪い習慣
コードをコピー
コードは次のとおりです:
class PersonUtils
{
public static function parsepersonName($format, $val)
{
if (strpos(",", $val) > 0) {
$person = new Person(); split(",", $val); // 値が最初であると仮定します
$person->setGivenName($parts[1]);リスト 4 の parsepersonName() メソッドを変更して、if 条件の外側で person オブジェクトを初期化し、有効な person オブジェクトが常に取得されるようにすることができます。ただし、得られるのは設定されたプロパティを持たない人物であり、それでもジレンマはあまり改善されません。
グッドプラクティス: 各モジュールは独自のエラーを処理します
呼び出し元に推測させず、パラメーターを事前に検証してください。設定されていない変数が有効な結果を生成できない場合は、変数をチェックして InvalidArgumentException をスローします。文字列を空にすることができない場合、または特定の形式にする必要がある場合は、形式を確認して例外をスローします。リスト 5 は、基本的な検証を示す parseperson() メソッドで例外といくつかの新しい条件を作成する方法を説明しています。
リスト 5. エラーをスローするための良い習慣
コードをコピー
コードは次のとおりです:
class InvalidPersonNameFormatException extends LogicException {}
class PersonUtils { public static function $format , $ val) { if (! $format) {
throw new InvalidPersonNameFormatException("無効な PersonName 形式です。");
}
if ((! isset($val)) || strlen($val) == 0 ) {
throw new InvalidArgumentException("解析するには null 以外の値を指定する必要があります。");
}
}
}
?>
最終的な目標は、人々が理解することなくクラスを使用できるようにすることです。使い方。 。何かを間違って使用していたり、期待どおりに使用していなかったとしても、なぜ機能しないのかを推測する必要はありません。良き隣人として、クラスを再利用する人には特別な機能がないことを知っておく必要があるため、推測の問題を解決する必要があります。
メデューサを見ないようにする
OO の概念について初めて学んだとき、インターフェイスが本当に役立つかどうか非常に懐疑的でした。私の同僚は、インターフェイスを使用しないのはメデューサの頭を見るようなものだと例えてくれました。ギリシャ神話では、メドゥーサは蛇の髪をした怪物です。彼女を見た者は石になってしまう。メドゥーサを殺したペルセウスは、盾に映る彼女の影を見て石になることを避け、彼女と戦うことができました。
インターフェースはメデューサに対処するための鏡です。特定の具体的な実装を使用する場合、実装コードの変更に応じてコードも変更する必要があります。実装を直接使用すると、実質的にクラスが「石」になってしまうため、オプションが制限されます。
悪い習慣: インターフェースを使用しない
リスト 6 は、データベースから person オブジェクトをロードする例を示しています。これは人の名前を取得し、データベースから一致する Person オブジェクトを返します。
リスト 6. インターフェースを使用しない悪い習慣
コードをコピーします
コードは次のとおりです:
class DBpersonProvider
{ public function getperson($givenName, $familyName) { /* データベースに移動し、人物を取得します... */ $person = new Person();
$person->setPrefix("Mr.");
$person->setGivenName("John") );
return $person;
}
}
/* 個人データを取得する必要があります... */
$provider = new DBpersonProvider();
$person = $provider->getperson(" Doe");
echo($person->getPrefix());
echo($person->getGivenName());
?>
データベースから person をロードするコードは、環境の変化。たとえば、データベースから個人をロードすることは、アプリケーションの最初のバージョンでは機能するかもしれませんが、2 番目のバージョンでは、Web サービスから個人をロードする機能を追加することが必要になる場合があります。実際、このクラスは実装クラスを直接使用しており、非常に限られた変更しか加えられないため、「石」になっています。
グッド プラクティス: インターフェイスを使用する
リスト 7 は、ユーザーをロードする新しい方法を実装した後に変更されていないコード例を示しています。この例では、単一のメソッドを宣言する PersonProvider という名前のインターフェイスを示しています。何らかのコードが PersonProvider を使用する場合、そのコードは実装クラスを直接使用することを禁止されます。代わりに、実際のオブジェクトであるかのように PersonProvider を使用します。
リスト 7. インターフェイスを使用するための良い習慣
コードをコピーします
コードは次のとおりです:
interface PersonProvider
{
public function getperson($givenName, $familyName);
}
class DBPersonalProvider は PersonProvider を実装します
{
public function getperson($givenName, $familyName)
{
/* のふりをしますデータベースに行き、人物を取得します... */
$person = new Person();
$person->setGivenName("John"); return $person;
}
}
class PersonProviderFactory
{
public static function createProvider($type)
{
if ($type == 'database')
{
return new DBpersonProvider()
} else {
return new NullProvider();
}
}
}
$config = 'database';
/* 個人データを取得する必要があります... */
$provider = PersonProviderFactory::createProvider($config); $provider->getperson("John", "Doe");
echo($person->getGivenName());インターフェイスを使用する場合は、実装クラスへの直接参照を避けるようにしてください。代わりに、オブジェクトの外部のコンテンツを使用すると、正しい実装が提供されます。クラスが何らかのロジックに基づいて実装をロードする場合、すべての実装クラスの定義を取得する必要がありますが、それでは何も達成されません。
Factory パターンを使用して、インターフェイスを実装する実装クラスのインスタンスを作成できます。慣例により、ファクトリ メソッドは作成で開始され、インターフェイスを返します。ファクトリがどの実装クラスを返すかを判断するために必要なパラメータを取得します。
リスト 7 では、createProvider() メソッドは $type を取得するだけです。 $type がデータベースに設定されている場合、ファクトリは DBPersonalProvider のインスタンスを返します。データベースから人をロードする新しい実装では、ファクトリとインターフェイスを使用してクラスを変更する必要はありません。 DBPersonalProvider は PersonProvider インターフェイスを実装し、getPerson() メソッドの実際の実装を持ちます。
最も弱いリンクを悪用する
モジュールを疎結合することは良いことであり、これは変更をカプセル化できるプロパティの 1 つです。他の 2 つの習慣、「注意する」と「メデューサを見ないようにする」は、疎結合モジュールの構築に役立ちます。クラスの依存関係を減らす習慣を身につけて、クラスの疎結合を実現します。
悪い習慣: 密結合
リスト 8 では、依存関係を下げても、そのオブジェクトを使用するクライアントの依存関係が必ずしも下がるわけではありません。代わりに、この例では、正しいクラスへの依存関係を減らし、最小限に抑える方法を示します。
リスト 8. Address の密結合の悪い習慣
コードをコピーします
コードは次のとおりです。
require_once "./AddressFormatters.php";
class Address { private $addressLine1; private $city;
$this-> ;addressLine1 = $ line1
}
/* アクセサなど... */
public function get Country()
{
return $this->country
}
public function format($type)
{
if ($type = = "インライン") {
$formatter = new InlineAddressFormatter();
} else if ($type == "multiline") {
$formatter = new MultilineAddressFormatter();
$formatter = new NullAddressFormatter()
}
return $formatter->format($this->getAddressLine1(),
$this->getAddressLine2(),
$this->getCity(), $this-> getState(), $this->getPostalCode(),
$this->get Country());
}
}
$addr = new Address();
$addr->setAddressLine1("123 ");
$addr->setAddressLine2("Ste 200");
$addr->setCity("Anytown");
$addr->setState("AY");
$addr->setPostalCode ("55555- 0000");
$addr->set Country("US");
echo("n"); ->フォーマット("インライン"));
?>
Address オブジェクトの format() メソッドを呼び出すコードは見栄えが良いかもしれません。このコードで行うことは、Address クラスを使用し、format() を呼び出して完了するだけです。対照的に、Address クラスはそれほど幸運ではありません。正しい書式設定にはさまざまな書式設定メソッドの知識が必要です。これにより、特に他の人が format() メソッドの書式設定メソッド クラスの使用に興味がない場合、他の人による Address オブジェクトの再利用が難しくなる可能性があります。 Address を使用するコードには多くの依存関係がありませんが、Address クラスには多くのコードがあり、単なるデータ オブジェクトにすぎない可能性があります。
Address クラスは、Address オブジェクトのフォーマット方法を認識する実装クラスと密接に結合されています。
良い習慣: オブジェクト間を緩やかに結合する
優れた OO 設計を構築するときは、懸念の分離 (SoC) と呼ばれる概念を考慮する必要があります。 SoC とは、オブジェクトを実際に関心のあるものごとに分離することで結合を軽減する試みを指します。元の Address クラスでは、それをどのようにフォーマットするかを考慮する必要がありました。これは良いデザインではないかもしれません。ただし、Address クラスは Address の部分を考慮する必要があり、一部の書式設定メソッドはアドレスを正しく書式設定することに重点を置く必要があります。リスト 9 では、アドレスをフォーマットするコードがインターフェース、実装クラス、およびファクトリーに移動されており、「インターフェースを使用する」という習慣が身につきます。現在、AddressFormatUtils クラスは、書式設定メソッドの作成と住所の書式設定を担当します。他のオブジェクトは、書式設定メソッドの定義を尋ねることを気にせずに、Address を使用できるようになりました。
リスト 9. オブジェクト間の疎結合の良い実践例
コードをコピー コードは次のとおりです:
interface AddressFormatter
{
public function format($addressLine1, $addressLine2, $city , $state,
$postalCode, $country);
}
class MultiLineAddressFormatter は AddressFormatter を実装します
{
public function format($addressLine1, $state,
$postalCode, $country)
{
return sprintf ( "%sn%sn%s, %s %sn%s",
$addressLine1, $addressLine2, $city, $state, $postalCode, $country);
}
}
class InlineAddressFormatter は AddressFormatter を実装します
{
public関数 format($addressLine1, $addressLine2, $city, $state,
$postalCode, $country)
{
return sprintf("%s %s, %s, %s %s %s",
$addressLine1, $ addressLine2 , $city, $state, $postalCode, $country);
}
}
class AddressFormatUtils
{
パブリック静的関数 formatAddress($type, $address)
{
$formatter = AddressFormatUtils::createAddressFormatter($type) ;
return $formatter->format($address->getAddressLine1(),
$address->getAddressLine2(),
$address->getCity(), $address->getState(),
$ address ->getPostalCode(),
$address->get Country());
}
プライベート静的関数 createAddressFormatter($type)
{
if ($type == "inline") {
$formatter = new InlineAddressFormatter ( );
} else if ($type == "multiline") {
$formatter = new MultilineAddressFormatter();
}
return $formatter;
$addr = 新しい住所();
$addr->setAddressLine1("123 任意の街")
$addr->setAddressLine2("任意の街"); ) ;
$addr->setState("AY");
$addr->setPostalCode("55555-0000");
echo(AddressFormatUtils::formatAddress) ( "複数行", $addr);
echo("inline", $addr);
;もちろん、欠点は、パターンが使用されるたびに、成果物 (クラス、ファイル) の数が増加することを意味することです。ただし、この欠点は、各クラスのメンテナンスを減らし、再利用性を適切に保つ際のアーティファクトの量を減らすことによって補うことができます。
あなたはゴム、私は接着剤です
凝集性の高い OO デザインは、関連するモジュールに焦点を当てて編成されています。 「懸念事項」を理解することは、関数とクラスをどの程度密接に関連させるかを決定する際に重要です。
悪い習慣: 凝集度の低下
デザインの凝集度が低いと、クラスとメソッドがうまく整理されません。スパゲッティ コードという用語は、一緒にバンドルされ、凝集度が低いクラスやメソッドを表すためによく使用されます。リスト 10 は、スパゲッティ コードの例を示しています。比較的一般的な Utils クラスは、さまざまなオブジェクトを使用し、多くの依存関係を持ちます。多くの操作を実行するため、再利用が困難です。
リスト 10. 結束力を低下させる悪い習慣
コードをコピーします
コードは次のとおりです:
class Utils
{
public static function formatAddress($formatType, $address1,
$address2, $city, $state)
{
return "アドレス文字列"
}
public static function formatpersonName; ($formatType, $givenName,
$familyName)
{
return "some person name";
}
public static function parseAddress($formatType, $val)
{
// 実際の実装では値などが設定されます...
return new Address();
}
public static function parseTelephoneNumber($formatType, $val)
{
// 実際の実装では値などを設定します...
return new TelephoneNumber()
}
}
?> ;
良い習慣: 高い凝集性を活用する
高い凝集性とは、関連するクラスとメソッドをグループ化することを意味します。メソッドとクラスの両方の凝集性が高い場合、設計に影響を与えることなくグループ全体を簡単に分解できます。凝集性の高い設計は、結合を減らす機会を提供します。リスト 11 は、より適切にクラスに編成された 2 つのメソッドを示しています。 AddressUtils クラスには、Address クラスを操作するためのメソッドが含まれており、アドレス関連のメソッド間の高度な連携が示されています。同様に、PersonUtils には、特に Person オブジェクトを操作するためのメソッドが含まれます。凝集性の高いメソッドを備えたこれら 2 つの新しいクラスは、完全に独立して使用できるため、結合が非常に低くなります。
リスト 11. 凝集性を高める良い習慣
コードをコピーします コードは次のとおりです:
class AddressUtils
{
public static function formatAddress($formatType, $address1,
$ address2, $city , $state)
{
return "何らかのアドレス文字列";
}
public static function parseAddress($formatType, $val)
{
// 実際の実装では値などを設定します...
return new Address();
}
}
class PersonUtils
{
public static function formatpersonName($formatType, $givenName,
$familyName)
{
return "ある人の名前"
}
public static function parsepersonName($formatType, $val)
{
// 実際の実装では値などを設定します...
return new PersonName();
}
}
?>
伝播を制限します
私は、私が働いているソフトウェア チームについてよくコメントします (私がテクニカル ディレクターを務める) (またはアーキテクト) は、OO 言語の最大の敵はコピー アンド ペースト操作であると述べました。事前の OO 設計なしで使用すると、クラス間でコードをコピーすることほど破壊的なものはありません。あるクラスから次のクラスにコードをコピーする場合は、一度立ち止まって、クラス階層を使用して類似または同一の機能を利用する方法を検討してください。ほとんどの場合、適切に設計されていれば、コードの重複はまったく不要であることがわかります。
悪い習慣: クラス階層を使用しない
リスト 12 は、部分クラスの簡単な例を示しています。これらは重複したフィールドとメソッドから始まり、長期的にはアプリケーションの変更にはつながりません。 Person クラスに欠陥がある場合、実装が 2 つのクラス間でコピーされているように見えるため、Employee クラスにも欠陥がある可能性が高くなります。リスト 12. 階層を使用しない悪い習慣
コードをコピーする コードは次のとおりです。従業員 {
private $givenName;
private $familyName;
?>
正しい継承モデルを構築するための分析には通常、長い時間がかかるため、継承を習慣化するのは困難です。また、Ctrl+C と Ctrl+V を使用して新しい実装を構築するのにかかる時間はわずか数秒です。ただし、アプリケーションの実際の保守には多額の費用がかかるため、この時間の節約は、保守フェーズ中にすぐに相殺されることがよくあります。
良い習慣: 継承を活用する
リスト 13 では、新しい Employee クラスは person クラスを拡張しています。今後は、すべての共通メソッドが継承され、再実装されなくなります。さらに、リスト 13 は抽象メソッドの使用法を示し、基本機能を基本クラスに組み込む方法と、実装クラスが特定の関数を使用しないようにする方法を示しています。
リスト 13. 継承を使用する良い習慣
コードをコピーします
コードは次のとおりです:
抽象クラス person
{
private $givenName;
プライベート $familyName;
パブリック関数 setGivenName($gn)
{
$this->givenName = $gn;
}
パブリック関数 getGivenName()
{
return $this->givenName;
}
パブリック関数 setFamilyName($fn)
{
$this->familyName = $fn;
}
パブリック関数 getFamilyName()
{
return $this->familyName;
}
パブリック関数sayHello()
{
echo("こんにちは、私は ");
$this->introduceSelf();
}
抽象パブリック関数導入Self();
}
class Employee extends Person
{
private $role;
パブリック関数 setRole($r)
{
$this->role = $r;
}
パブリック関数 getRole()
{
return $this->role;
}
public function recruitSelf()
{
echo($this->getRole() . " " . $this->getGivenName() . " " .
$this->getFamilyName());
}
}
?>
使用モードを検討する
設計モードは、オブジェクトとメソッドの通常のやり取りを示し、それらが何らかの問題を解決できることを示しています。构建类
相互作用の単純な方法であり、他の人に確認する必要はなく、この説明の設計から利益を得ることができます。有ただし、一般的には、次の条件が満たされた場合に 1 つのオブジェクトのみを考慮できることが知られています。
良い転送:同時にモード内で形成されるオブジェクトを追加します。
一般に、以下の操作を実行するときは、使用モードを検討します:
先に構築します
モードの種類に応じて。
Factory、Singleton、Facade などのモード名を使用します。
モデルの大部分を削除し、その後追加の実行を開始します。より堅固で、より簡単に、より簡単に展開できるアプリケーションです。
転送を制限します。
モードの使用を検討します。
これらのアプリケーションを適切に作成して使用すると、アプリケーション プログラムの大量の影響が発生する可能性があります。
http://www.bkjia.com/PHPjc/321168.html
www.bkjia.com
true
http://www.bkjia.com/PHPjc/321168.html
技術記事
OO 原始作成プログラムをまだ実行していない場合、PHP の面方向オブジェクト (OO) の言語特性を使用すると、この 7 つのヘルプは、このプログラムと OO プログラムの間に実行されます...