2011-12-16 10 views
1

私は見通しオファーを含む簡単なプロジェクトに取り組んでいます。このプロジェクトは、Prospectオブジェクトを使用してリストの電子メールアドレスを管理し、オファーオブジェクトを使用してキャンペーンを管理するサードパーティのメーリングリストプロバイダと統合されます。メーリングリストのマネージャークラスをより疎結合にするにはどうすればよいですか?

私の懸念事項の1つは、メーリングリストのプロバイダ(MailChimpなど)がサービスの提供を停止するか、今後利用規約を変更することがあるということです。自分のソフトウェアをプロバイダに依存させるのではなく、別のメーリングリストプロバイダを使用する別のクラスを使用して再実装できる汎用インタフェースに依存させたいと考えています。そうすれば、そのようなことが起こったら、私は単に新しいクラスを作成し、古いクラスの代わりにインスタンス化するだけです。

これは実装が簡単なようです。以下に含まれる抽象クラスは、ProspectオブジェクトまたはOfferオブジェクトのいずれかを取る抽象メソッドを定義し、それらにジェネリックメーリングリスト関連の関数を行い、必要に応じてtrue/falseまたは整数値を返します。このインターフェイスは、私のアプリケーションのニーズを十分に満たす必要があります。

<?php 
/** 
* MailingList file. 
* 
* Contains the class definition for the abstract class Monty_MailingList. 
* @author Lewis Bassett <lewis[email protected]> 
* @version 0.1 
* @package Monty 
*/ 

/** 
* Represents the interface for all MailingList classes. 
* 
* Adhereing to this interface means that if a MailingList provider 
* (e.g., MailChimp) stops a service, a new class can extend this interface and 
* be replace the obsolete class with no need to modify any of the client code. 
* 
* @author Lewis Bassett <[email protected]> 
* @version 0.1 
* @package Monty 
* @copyright Copyright (c) 2011, Bassett Providentia 
*/ 
abstract class Monty_MailingList 
{ 
    /** 
    * Adds the passed prospect to the mailing list, or returns false if the 
    * prospect already exists. Throws an error if the prospect could not be 
    * added for any reason (other than it already existing). 
    * 
    * @param Monty_Prospect $prospect The prospect object to be added to the 
    * mailing list. 
    * @return bool Whether or not the prospect was added. 
    */ 
    abstract public function addProspect(Monty_Prospect $prospect); 

    /** 
    * Updates the properties stored on the mailing list of the passed prospect, 
    * or returns false if no data was updated. If the prospect is not found, a 
    * they are added to the list. Throws an error if the prospect could not be 
    * added or updated for any readon. 
    * 
    * @param Monty_Prospect $prospect The prospect object whose mailing list 
    * data is to be updated. 
    * @return bool Whether or not the prospect was updated. 
    */ 
    abstract public function updateProspect(Monty_Prospect $prospect); 

    /** 
    * Returns true if the passed prospect object could be found on the mailing 
    * list. 
    * 
    * @param Monty_Prospect $prospect The prospect object to be searched for. 
    * @return bool Whether or not the prospect was found. 
    */ 
    abstract public function findProspect(Monty_Prospect $prospect); 

    /** 
    * Deletes the passed prospect from the mailing list, or returns false if 
    * the passed object is not found on the mailing list. 
    * 
    * @param Monty_Prospect $prospect The prospect to be deleted. 
    * @return bool Whether or not the prospect was deleted. 
    */ 
    abstract public function deleteProspect(Monty_Prospect $prospect); 

    /** 
    * Creates a campaign for the passed offer object, or returns false if the 
    * campaign already exists. Throws an error if the campaign could not be 
    * created for any reason (other than it already existing). 
    * 
    * @param Monty_Offer $offer The offer to be created. 
    * @return bool Whether or not the offer was created. 
    */ 
    abstract public function createOffer(Monty_Offer $offer); 

    /** 
    * Sends the campaign for the passed offer object, or returns false if the 
    * campaign could not be sent for a reasonable reason (run out of credit or 
    * something). If the campaign does not yet exist, it is created. Throws an 
    * error if the campaign could not be created, or an was not sent for an 
    * unknown reason. 
    * 
    * @param Monty_Offer $offer The offer to be sent. 
    * @return bool Whether or not the offer was sent. 
    */ 
    abstract public function sendOffer(Monty_Offer $offer); 

    /** 
    * Returns true if a campaign for the passed offer object could be found on 
    * the mailing list. 
    * 
    * @param Monty_Offer $offer The offer to be searched for, 
    * @return bool Whether or not the offer was found. 
    */ 
    abstract public function findOffer(Monty_Offer $offer); 

    /** 
    * Returns the ammount of opens registered for the passed offer. Throws an 
    * error if a campaign is not found for the passed offer. 
    * 
    * @param Monty_Offer $offer The offer in question. 
    * @return int The ammount of registered opens for that offer. 
    */ 
    abstract public function getOfferOpens(Monty_Offer $offer); 

    /** 
    * Returns the ammount of clicks registered for the passed offer. Throws an 
    * error if a campaign is not found for the passed offer. 
    * 
    * @param Monty_Offer $offer The offer in question. 
    * @return int The ammount of registered clicks for that offer. 
    */ 
    abstract public function getOfferClicks(Monty_Offer $offer); 

    /** 
    * Returns the ammount of bounces registered for the passed offer. Throws an 
    * error if a campaign is not found for the passed offer. 
    * 
    * @param Monty_Offer $offer The offer in question. 
    * @return int The ammount of registered bounces for that offer. 
    */ 
    abstract public function getOfferBounces(Monty_Offer $offer); 

    /** 
    * Returns the ammount of unsubscribes registered for the passed offer. 
    * Throws an error if a campaign is not found for the passed offer. 
    * 
    * @param Monty_Offer $offer The offer in question. 
    * @return int The ammount of registered unsubscribes for that offer. 
    */ 
    abstract public function getOfferUnsubscribes(Monty_Offer $offer); 
} 

ここでジレンマがあります。

将来、私のアプリケーションとメーリングリストプロバイダとの間で渡されるデータは変更される可能性がありますが、どこでもインターフェイスを変更し続ける必要はありません。オブジェクトをメソッドに渡すことで、どこにでもインターフェイスを変更することなく、新しいプロパティを使用できるようにメソッドを変更できます。これは非常に柔軟な解決策のようです。

しかし

私は必ずしもプロスペクトまたはオファークラスを使用しない場合があります他のプロジェクトでこのクラスを使用したいと思います。上記のインタフェースは、クラスの観点から、クラスが渡されているオブジェクトに依存しているという点で、緊密に結合されているようです。

オブジェクトにメソッドを渡す柔軟性をどのように保つかもしれないのですが、他のプロジェクトでも簡単に再利用できるクラスはありますか?

これまでにお読みいただきありがとうございます。私は常に自分のスキルを向上させるために探しています。私はこれをより良くする方法についてのあなたの洞察に非常に感謝しています。

答えて

1

いくつかのより多くの思考の後、私は私が最善の解決策と思われるものを作ってみた、デザインパターンの中からいくつかのインスピレーションのおかげ:再利用可能なオブジェクト指向ソフトウェアの要素(Erich Gamma氏、リチャードヘルム、ラルフ・ジョンソンとJohn Vlissides)。

私は今、2つの抽象クラスがあります。

MailingListRecipientは - メーリングリストの受信者を代表するオブジェクトのためのインタフェースを定義します。すべてのクライアントコードはこのインタフェース用に作成され、この抽象コードのどの子クラスがそれを実装しているかは気にしません。姓、姓、電子メールアドレスを設定し、メーリングリストの受信者を追加、更新、削除、検索する方法があります。

MailingListMessage - メーリングリスト上のメッセージを表すオブジェクトのインタフェースを定義し、いくつかのセッターメソッドといくつかのアクションが定義されます。ここでも、クライアントコードはこのインタフェース用に記述され、サブクラスがどのように実装するかは気にしません。

私は、抽象ファクトリクラスを持っています:

MailingListFactory - これは私のクライアントのコード全体MailingListRecipientMailingListMessageオブジェクトを作成します。

ので、実際の実装のために、私が作成します。

MailChimpRecipient - MailChimpリストの受信者を表すために。ここのコードはMailingListRecipientで定義されたインターフェイスに準拠し、そのオブジェクトはそのコンストラクタにAPIキーとListIdが必要です。

MailChimpMessage - MailChimpリストにメッセージを表示する。ここのコードは、MailingListMessageで定義されているインターフェイスに準拠します。このオブジェクトも、そのコンストラクタにAPIキーとListIdが必要です。

私のクライアントコードは、上記の2つのオブジェクトのいずれとも対話しません。 - MailChimpの受信者とメッセージを作成するために使用さ

MailChimpFactory:代わりに、私の設定ファイルの1つに、私はのオブジェクトを作成します。オブジェクトはAPIキーとListIdを必要とし、MailChimp固有のオブジェクトを作成するためにこれらを上記の2つのクラスのコンストラクタに渡します。その時から

$recipient = $mailingListFactory->createMailingListRecipient(); 

$mailingListFactory = new MailChimpFactory($apiKey, $listId); 

その後、私のクライアントコード全体で、新しい受信者とメッセージは、このように作成されます

だから、私の設定コードで、私はファクトリオブジェクトを作成します

$recipient->setForename('Lewis'); 
$recipient->setEmailAddress('[email protected]'); 
$recipient->add(); 

MailChimpが突然彼らのサービスを停止、またはIは、D場合:、物事を設定し、アクションを行うことができるでしょうに新しいプロバイダを使うMailingListRecipientとMailingListMessageという新しい子クラスを作成するだけです。それらのインターフェイスは同じになり、クライアントコードはそれが違うということを知らないでしょう。

次に、新しいクラスの新しい受信者とメッセージオブジェクトを作成するMailingListFactoryの新しい子クラスを作成します。私のコードの残りの部分は、私の抽象工場で定義されたインタフェースのために書かれているので、他に何も変更する必要はありません

$mailingListFactory = new newMailingListProviderFactory($username, $password); 

:私が行う必要がありますすべては私の設定ファイルでインスタンス化を変更です。

抽象的なファクトリを使用することで、コードがmailChimpRecipientオブジェクトとnewMailingListProviderMessageオブジェクトを使用している状況にならないようになります。

これが私の目標の両方を満たしている:

Interchangeablity - 私は私のメーリングリストのクラスを入れ替えることができ、コードは以前と同じように動作します。

再利用性 - 私はこれらのクラスをとり、他のプロジェクトで使用することができます。

これはこれを行う最もエレガントな方法です。他の誰かがより良い方法を持っているなら、私はそれについて聞いてみたいと思います。みなさんのお返事ありがとうございます。

1

あなたはより一般的なアプローチをしたい場合は、あなたが代わりの見通し、および電子メールメッセージ代わりの申し出、すなわち、(任意の)メーリングリストへの汎用インタフェースを追加したクラスを作成します。次に、Monty_MailingListに汎用リストを継承させます。

+0

私はPersonクラスとEmailMessageクラスを作成し、それらをPersonとEmailMessageを使用していたメソッドに引数として渡します。そこで、自分自身をパラメータとして渡したMonty_Prospectクラス内で、新しいPersonクラスをインスタンス化し、その代わりに渡しますか? –

1

私はエミールに一部同意します。

ここで問題を混在させています。あなたのクラスはメーリングリストと呼ばれ、見込み客やオファーとは何も関係がありませんが、送信したい人とコンテンツがあります。

プロスペクトとオファーは、Webページにレンダリングされたときに別の表現を持つことができるため、電子メールでユーザーに送信される1つの表現を持つことができるビジネスロジックモデルです。メールからの統計情報の収集も別物です。

私が普段はしていないので、私が同意しないことの1つは継承点です。私はここで何も継承しませんが、その部分を処理し、代わりに合成を使用する別々のクラスを作成します。

+1

構図はそれを行う別の方法ですが、見通しやオファーを追加する特別なメーリングリストを実際に望んでいるので、継承はここでの優先的なアプローチです。合成は、それを実行するための不可欠な方法であり、実際には、見込み客/オファーリストが一般的なメーリングリストを引数として取る必要があるため、実際にコードをより緊密に結合します(後でジェネリックリストを別の場所に送信するとどうなりますか? 「見込み客」は魔法のように他のタイプの人ですか?)ルイスが本当にオブジェクト指向のコーディングを使用したいのであれば、継承はここで使うべきものです、IMHO。 –

+1

まあ、議論したくないが、2つのことがある。 1.私は、これを適切に設計し、そのレベルで議論するには、問題の詳細な洞察が必要だと思います。とにかく、あなたは両方の方法でそれをうまくやることができると思います。 2.真のオブジェクト指向プログラミングを望むなら、ほぼすべてのケースで継承より合成を優先します。 – ivanjovanovic

+1

1.あなたは絶対に正しいですが、ユースケースに最も適したアプローチを決定するのはルイスまたは彼のチームです。 2.私は同意しませんが、Monty_MailingListがGeneric_MailingListであるか、Generic_MailingListがその作業を行う必要があるかどうかは、ポイント#1を表現する別の方法です。これについて議論するいくつかの他のトピックがあります:http://stackoverflow.com/questions/49002/prefer-composition-over-inheritance http://stackoverflow.com/questions/269496/inheritance-vs-aggregationと多くの。 –

関連する問題