99

PHP5がまだ多重継承をサポートしていないという事実を回避するための、適切でクリーンな方法を探しています。クラス階層は次のとおりです。

メッセージ
-- TextMessage
-------- InvitationTextMessage
-- EmailMessage
-------- InvitationEmailMessage

2 種類の Invitation* クラスには多くの共通点があります。両方が継承する共通の親クラス Invitation が欲しいです。残念ながら、現在の祖先である TextMessage および EmailMessage と多くの共通点もあります。ここでの多重継承に対する古典的な欲求。

問題を解決するための最も軽量なアプローチは何ですか?

ありがとう!

4

11 に答える 11

144

アレックス、多重継承が必要な場合のほとんどは、オブジェクト構造が多少間違っていることを示しています。あなたが概説した状況では、クラスの責任が広すぎることがわかります。Message がアプリケーション ビジネス モデルの一部である場合、出力のレンダリングを気にする必要はありません。代わりに、責任を分割し、テキストまたは HTML バックエンドを使用して渡されたメッセージを送信する MessageDispatcher を使用できます。私はあなたのコードを知りませんが、このようにシミュレートさせてください:

$m = new Message();
$m->type = 'text/html';
$m->from = 'John Doe <jdoe@yahoo.com>';
$m->to = 'Random Hacker <rh@gmail.com>';
$m->subject = 'Invitation email';
$m->importBody('invitation.html');

$d = new MessageDispatcher();
$d->dispatch($m);

このようにして、 Message クラスに特殊化を追加できます。

$htmlIM = new InvitationHTMLMessage(); // html type, subject and body configuration in constructor
$textIM = new InvitationTextMessage(); // text type, subject and body configuration in constructor

$d = new MessageDispatcher();
$d->dispatch($htmlIM);
$d->dispatch($textIM);

MessageDispatcher は、type渡された Message オブジェクトのプロパティに応じて、HTML またはプレーン テキストとして送信するかどうかを決定することに注意してください。

// in MessageDispatcher class
public function dispatch(Message $m) {
    if ($m->type == 'text/plain') {
        $this->sendAsText($m);
    } elseif ($m->type == 'text/html') {
        $this->sendAsHTML($m);
    } else {
        throw new Exception("MIME type {$m->type} not supported");
    }
}

要約すると、責任は 2 つのクラスに分割されます。メッセージの設定は InvitationHTMLMessage/InvitationTextMessage クラスで行い、送信アルゴリズムはディスパッチャに委譲します。これは戦略パターンと呼ばれます。詳細については、こちらを参照してください

于 2008-09-18T09:53:48.843 に答える
15

「is-a」関係を「has-a」関係に置き換えることはできますか? 招待状にはメッセージが含まれる場合がありますが、必ずしもメッセージである必要はありません。招待状が確認される場合があり、メッセージモデルとは相性が悪いです。

それについてもっと知る必要がある場合は、「構成と継承」を検索してください。

于 2008-09-18T08:45:27.790 に答える
10

このスレッドでフィルを引用できれば...

PHP は、Java と同様に多重継承をサポートしていません。

PHP 5.4 で登場するのは、この問題の解決策を提供しようとするトレイトです。

それまでの間、クラスの設計を再考することをお勧めします。クラスに拡張 API を追加したい場合は、複数のインターフェイスを実装できます。

そしてクリス……。

PHP は実際には多重継承をサポートしていませんが、それを実装する (やや面倒な) 方法がいくつかあります。いくつかの例については、次の URL を確認してください。

http://www.jasny.net/articles/how-i-php-multiple-inheritance/

どちらにも便利なリンクがあると思いました。トレイトやミックスインを試すのが待ちきれません...

于 2012-03-22T07:15:58.597 に答える
7

Symfony フレームワークには、この.

「デザインパターン」の答えは、共有機能を別のコンポーネントに抽象化し、実行時に構成することです。Invitation 機能を、継承以外の方法で Message クラスに関連付けられるクラスとして抽象化する方法を考えてみてください。

于 2008-09-18T08:43:24.770 に答える
4

これを解決する方法として、PHP5.4の特性を使用しています。 http://php.net/manual/en/language.oop5.traits.php

これにより、extendsを使用した従来の継承が可能になりますが、共通の機能とプロパティを「トレイト」に配置することもできます。マニュアルにあるように:

特性は、PHPなどの単一継承言語でコードを再利用するためのメカニズムです。トレイトは、開発者が異なるクラス階層に存在するいくつかの独立したクラスでメソッドのセットを自由に再利用できるようにすることで、単一継承のいくつかの制限を減らすことを目的としています。

于 2012-11-15T12:02:11.673 に答える
3

これは質問と解決策の両方です....

魔法の _call () はどうですか?_get()、__set() メソッド? このソリューションはまだテストしていませんが、multiInherit クラスを作成するとどうなりますか。子クラスの保護変数には、継承するクラスの配列を含めることができます。マルチインターフェイス クラスのコンストラクターは、継承される各クラスのインスタンスを作成し、_ext などのプライベート プロパティにリンクすることができます。__call() メソッドは、_ext 配列内の各クラスで method_exists() 関数を使用して、呼び出す正しいメソッドを見つけることができます。__get() および __set を使用して内部プロパティを検索できます。または、参照を持つ専門家であれば、子クラスのプロパティと継承されたクラスを同じデータへの参照にすることができます。オブジェクトの多重継承は、それらのオブジェクトを使用するコードに対して透過的です。また、_ext 配列がクラス名でインデックス付けされている限り、内部オブジェクトは必要に応じて継承されたオブジェクトに直接アクセスできます。私はこのスーパークラスを作成することを思い描いていましたが、まだ実装していません。これが機能する場合、さまざまな悪いプログラミング習慣の開発につながる可能性があると感じているからです。

于 2010-10-20T07:52:24.523 に答える
3

デコレータ パターンが適しているように思えますが、詳細がわからないとわかりません。

于 2008-09-18T08:43:10.060 に答える
1

あなたが何をしているのかを明確にするために、いくつか質問があります。

1) メッセージ オブジェクトには、本文、受信者、予定時刻などのメッセージだけが含まれていますか? 2) Invitation オブジェクトで何をするつもりですか? EmailMessage と比較して特別に扱う必要がありますか? 3) もしそうなら、何が特別なのですか? 4) その場合、なぜメッセージの種類によって招待状の処理が異なる必要があるのですか? 5) ウェルカム メッセージまたは OK メッセージを送信したい場合はどうしますか? それらも新しいオブジェクトですか?

あまりにも多くの機能を、メッセージの内容を保持することのみに関係するオブジェクトのセットに結合しようとしているように聞こえます。私には、招待状と通常のメッセージに違いはありません。招待に特別な処理が必要な場合、それはメッセージ タイプではなく、アプリケーション ロジックを意味します。

たとえば、私が構築したシステムには、SMS、電子メール、およびその他のメッセージ タイプに拡張された共有ベース メッセージ オブジェクトがありました。ただし、これらはさらに拡張されませんでした。招待メッセージは、メール タイプのメッセージを介して送信される事前定義されたテキストにすぎませんでした。特定の招待状アプリケーションは、招待状の検証およびその他の要件に関係します。結局のところ、メッセージ X を受信者 Y に送信するだけで済みます。受信者 Y は、それ自体が個別のシステムである必要があります。

于 2008-09-18T14:13:19.453 に答える
0

Javaと同じ問題。その問題を解決するために、抽象関数を持つインターフェイスを使用してみてください

于 2008-09-18T08:45:27.230 に答える
0

PHP はインターフェースをサポートしています。ユースケースによっては、これは良い賭けになる可能性があります。

于 2008-09-18T08:47:54.400 に答える
-1

Message クラスのすぐ下にある Invitation クラスはどうでしょうか。

したがって、階層は次のようになります。

メッセージ
--- 招待状
------ TextMessage
------ EmailMessage

Invitation クラスに、InvitationTextMessage と InvitationEmailMessage にあった機能を追加します。

招待は実際にはメッセージのタイプではなく、メッセージの機能であることはわかっています。したがって、これが良い OO 設計であるかどうかはわかりません。

于 2012-05-23T21:02:12.567 に答える