形質の使用方法

最近、私が書いている新しいプロジェクトで特性を使用することについて話をするように何人かの人々に頼まれました。 ほぼ同時に、ラファエル・ドムスは、私たちが気付いていない複雑な認知プロセスに関する彼の新しいスピーチを見せてくれました。 私たちの脳はすべてを混ぜ合わせた大きな袋なので、結果は私がどのように特性を使用し、どのようにそれらが必要かを決定する方法をカバーしようとする投稿です。



インパクトと抽象化



最初にすべきことは、Michael Nygardによる投稿「Abstraction or Leverage」を読むことです。 これは素晴らしい記事です。



時間に余裕がない場合、投稿の主なポイントは、コードの一部(関数、クラス、メソッドなど)を抽象化またはインパクトのいずれかに向けることができるということです。 の違い:





一般的な抽象化はリポジトリパターンです。オブジェクトがどのように保存されているか、どこにいるのかは気にしません。 詳細はリポジトリ概念のにあります。



全体的な影響は、フレームワークのコントローラーの基本クラスのようなものになります。 実装を隠しませんが、作業を簡単にするクールな機能を追加するだけです。



上記の投稿は、抽象化と効果の両方が優れていると述べています。 しかし、抽象化の方が少し優れています。なぜなら、それは常に行動する能力を与え、その影響は抽象化を与えないからです。 ただし、良い抽象化は作成するのが面倒であり、すべてのレベルで可能ではないことを付け加えます。 したがって、これは妥協です。



これはどのように特性に関係していますか?



言語の一部の機能は、インパクトまたは抽象化の作成において他の機能よりも優れています。 たとえば、インターフェイスは、抽象化の構築と適用に完全に役立ちます。



一方、継承は影響を与えるのに優れています。 これにより、各メソッドをコピーまたは抽出することなく、親コードの一部を再定義し、クラスのコードを使用することができます(必ずしも抽象的ではありません)。 だから、最初の質問に答えて、いつ特性を使用できますか?



抽象化ではなく、インパクトを作成したいときに、特性を使用します。



時々。



時々?



ベンジャミン・エバリーは、 特性には基本的に静的アクセスと同じ問題があるという良い議論をしました。 それらを置き換えたり再定義したりすることはできません;それらはテストするのが率直に難しいです。



しかし、それでも静的メソッドは便利です。 状態のない関数があり、その関数を別の実装に置き換えたくない場合、静的にすることは何の問題もありません。 名前付きコンストラクター(空のオブジェクトが必要になることはめったにありません)、または明確に定義された入力/出力、ステートレス、決定論的な数学演算の配列/結果の取得:これらはすべて興味深いものです。 メソッドではなく静的な状態は本当の悪です。



トレイトにはほぼ同じ制限があり、さらにクラス内でのみ使用できます。 オブジェクトよりもグローバルです。



これにより、特性に追加機能が追加されます。特性は、混合されたクラスの内部状態で動作(読み取りおよび書き込み)できます。 場合によっては、これにより静的メソッドよりも適切になります。



たとえば、私は多くの場合、本質的にドメインイベントの生成を使用します。



trait GeneratesDomainEvents { private $events = []; protected function raise(DomainEvent $event) { $this->events[] = $event; } public function releaseEvents() { $pendingEvents = $this->events; $this->events = []; return $pendingEvents; } }
      
      





このコードをリファクタリングして抽象化できますが、静的メソッドとは異なり、オブジェクトのローカル状態で特性がどのように機能するかの良い例です。 イベントの配列を盲目的に処理したり、オブジェクトから移動したりすることは望ましくありません。 おそらく、モデル内に別の抽象化を追加したくないでしょうし、もちろん、このテンプレートコードをどこにでもコピーしたくはありません。 そして、ここで再び特性は私たちを助けます。



他の実用的な例には、カスタム関数のロギング、複数のプロパティの同時ダンプ、または一般的な反復/検索ロジックが含まれます。 これらの問題はすべて親クラスで解決できますが、これについては後ほど説明します。



そのため、このような場合には特性が適切な代替となりますが、これは静的メソッドが役に立たないという意味ではありません。 実際、オブジェクトの内部状態を変更する必要がない場合は、常に安全なため、静的メソッドを使用することを好みます。 静的メソッドは、テストにおいてもはるかに便利であり、モッククラスを必要としません。



ステートメントを作成することは、静的メソッドを好む場合の良い例です。ただし、通常は特性に入れることができます。 Assertion::positiveNumber($int)



を使用すると上記の利点が得られ、呼び出されたクラスが何をするのかを理解しやすくなります。



同様の文の方法がある場合、それらを特性に変換することは常に魅力的ですが、そのようなコードはすでに「臭い」を始めています。 おそらくこのメソッドにはいくつかのパラメーターが必要で、それらを渡すのにうんざりしています。 おそらく$this->foo



チェックするには、 $this->bar



値が必要です。 これらのいずれの場合でも、クラスのリファクタリングがより良い代替手段になります。 効果が抽象化に取って代わる場合は、常に優れていることを忘れないでください。



そこで宣言します。オブジェクトの内部状態へのアクセスを必要とする影響が必要な場合は、特性を使用します。



親クラス



リストしたものはすべて、継承によって実装することもできます。 EventGeneratingEntity



イベント配列が実際に個別になるためEventGeneratingEntity



おそらくこのようなアプローチの方が優れているでしょう。 ただし、特性は、単一の基本クラスの代わりに複数の継承を許可します。 機能セットに加えて、このアプローチには他に良い議論がありますか?



他の条件が同じであれば、「Is-A vs. Has-A」のようなルールに導かれます。 もちろん、これは正確なルールではありません。なぜなら、 特性は構成ではなく、合理的なガイドだからです。



つまり、ある種のオブジェクトに固有の関数には親クラスを使用する必要があります。 親クラスは、コードの意味を他の開発者によく伝えます。「従業員は人です」。 影響が必要な場合、これはコードがコミュニケーション的であってはならないという意味ではありません。



オブジェクトの他の非コア機能(ロギング、イベントなど)の場合、トレイトは適切なツールです。 これらはクラスの性質を決定するものではありません;これらは補助関数であり、さらに良いのは実装の詳細です。 特性から得られるものはすべて、オブジェクトの主な目標のサービスである必要があり、特性が機能の重要な部分になることはありません。



そのため、イベント生成の場合、イベントの作成は補助機能であるため、私はまだ特性を好みます。



インターフェース



インターフェイスを作成せずにクラスを拡張したり、トレイトを作成したりすることはめったにありません。



この規則に従えば、特性はインターフェース分離の原則をうまく補完することがわかります。 追加機能用のインターフェイスを定義し、トレイに単純なデフォルト実装を作成するのは簡単です。



これにより、ターゲットクラスは独自のバージョンのインターフェイスを実装したり、重要でない場合にデフォルトの特性を使用したりできます。 パターンを選択し、抽象度を低くすることを選択する場合、特性は強力な味方になります。



それでも、コードにインターフェイスを実装するクラスが1つしかなく、変更する予定がない場合は、その機能を直接実装してください。特性については心配しないでください。 このようにして、コードをより読みやすく保守しやすくします。



特性を使用しない場合



正直なところ、私は特性をあまり頻繁に使用していません。おそらく数か月ごとに、プロジェクトで絶えず作業する特性を作成しています。 私が概説したこのすべてのヒューリスティック(内部状態へのアクセスを必要とする影響)は非常にニッチです。 頻繁に使用する場合は、一歩後退してプログラミングスタイルを再考する必要があります。 何千ものクラスが実現するのを待っている可能性が十分にあります。



スタイルの好みのために特性を使用したくない場所がいくつかあります。





そして最後に、特性は抽象化を意味せず、それらは構成ではないことを覚えておく必要がありますが、それでもなお、それらはあなたの楽器の中で場所を取る権利を持っています。 これらは、小規模な実装やコードの複製にデフォルトの影響を与えるのに役立ちます。 「備蓄」コードの兆候を感じたらすぐに、より良い抽象化のためにそれらを再編成する準備を常にしてください。



All Articles