我正在开展一个涉及潜在客户和优惠的简单项目。该项目将与第三方邮件列表提供商集成,该提供商将使用Prospect对象管理列表中的电子邮件地址,并提供对象来管理广告系列。
我担心的一点是,任何邮件列表提供商(例如MailChimp)可能会决定停止提供服务,或者将来更改条款。我不想让我的软件依赖于提供程序,而是希望它依赖于通用接口,该接口可以使用不同的类重新实现,该类使用不同的邮件列表提供程序。这样,如果确实发生了这样的事情,我只会编写一个新类并实例化代替旧类。
这似乎很容易实现。我的抽象类(包含在下面)定义了抽象方法,这些方法接受Prospect或Offer对象,并为它们执行通用的邮件列表相关函数,在需要时返回true / false或整数值。这个界面应该能够很好地满足我的应用需求。
<?php
/**
* MailingList file.
*
* Contains the class definition for the abstract class Monty_MailingList.
* @author Lewis Bassett <lewis.bassett@bassettprovidentia.com>
* @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 <lewis.bassett@bassettprovidentia.com>
* @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);
}
这就是困境。
将来,我的应用程序邮件列表提供程序之间传递的数据可能会发生变化,但是,我不希望不得不随时随地更改界面。通过将对象传递给方法,我可以修改方法以在新属性可用时使用它们,而无需在任何地方更改接口。这似乎是一个非常灵活的解决方案。
但是
我想在其他项目中使用此类,可能不一定使用Prospect或Offer类。从类的角度来看,上面的接口似乎过于紧密耦合,因为类依赖于传递给它的对象。
有没有人对如何保持将对象传递给方法的灵活性有任何建议,但有一个我可以轻松地重用于其他项目的类?
非常感谢你们已经阅读了这篇文章!我一直在寻求提高自己的技能,我非常感谢你对我如何做得更好的见解。
答案 0 :(得分:1)
如果您想要更通用的方法,请创建一个类,您可以在其中添加人而非潜在客户,电子邮件而不是商品,即通用界面(任何)邮件列表。然后让你的Monty_MailingList继承通用列表。
答案 1 :(得分:1)
我在某种程度上同意埃米尔的意见。
您正在混淆这些问题。您的课程称为邮件列表,其中不应包含潜在客户和优惠,但包含您要发送的人员和内容。
前景和优惠是业务逻辑模型,可以通过电子邮件将一个表示发送给用户,因为他们可以在呈现到网页时具有其他表示。从邮件中收集统计数据也是分开的。
我不同意的一点是继承点,因为我通常不会这样做。我不会在这里继承任何东西,而是创建单独的类来处理它们的部分并改为使用组合。
答案 2 :(得分:1)
经过一番思考之后,我想出了我认为最好的解决方案,感谢来自设计模式的一些灵感:可重复使用的面向对象软件的元素(Erich Gamma,Richard Helm) ,Ralph Johnson和John Vlissides)。
我现在有两个抽象类:
MailingListRecipient - 定义代表邮件列表收件人的对象的接口。将为此接口编写所有客户端代码,并且不关心此抽象代码的子类实现它。它将具有设置姓名,电子邮件地址以及在邮件列表中添加,更新,删除和查找收件人的方法。
MailingListMessage - 定义将代表邮件列表上的邮件的对象的接口,并将定义一些setter方法和一些操作。同样,将为此接口编写客户端代码,而不关心子类如何实现它。
然后我会有一个抽象的工厂类:
MailingListFactory - 这会在我的客户端代码中创建 MailingListRecipient 和 MailingListMessage 对象。
因此,对于真正的实现,我将创建:
MailChimpRecipient - 代表MailChimp列表中的收件人。此处的代码将遵循 MailingListRecipient 定义的接口,并且该对象在其构造函数中需要API密钥和ListId。
MailChimpMessage - 表示MailChimp列表中的邮件。此处的代码将遵循 MailingListMessage 定义的接口,此对象在其构造函数中也需要API密钥和ListId。
我的客户端代码不会与上述两个对象中的任何一个进行交互。相反,在我的一个设置文件中,我将创建一个对象:
MailChimpFactory - 用于创建MailChimp收件人和邮件。该对象需要API密钥和ListId,然后将这些传递给上述两个类的构造函数,以便创建MailChimp特定对象。
因此,在我的设置代码中,我将创建一个工厂对象:
$mailingListFactory = new MailChimpFactory($apiKey, $listId);
然后,在我的客户端代码中,将创建新的收件人和消息:
$recipient = $mailingListFactory->createMailingListRecipient();
从那时起,它将能够设置并执行操作:
$recipient->setForename('Lewis');
$recipient->setEmailAddress('lewis@example.com');
$recipient->add();
如果MailChimp突然停止了他们的服务,或者我决定使用另一个邮件列表提供者,我将只创建使用新提供者的MailingListRecipient和MailingListMessage的新子类 - 他们的接口将是相同的,并且客户端代码赢了不知道或关心它是不同的。
然后我将创建一个新的MailingListFactory子类,它将创建新类的新Recipient和Message对象。我需要做的就是更改设置文件中的实例化:
$mailingListFactory = new newMailingListProviderFactory($username, $password);
因为我的其余代码是为抽象工厂中定义的接口编写的,所以不需要更改任何其他代码。
使用抽象工厂可确保我不会遇到代码使用mailChimpRecipient对象和newMailingListProviderMessage对象的情况。
这符合我的目标:
Interchangeablity - 我可以交换我的邮件列表类,代码仍然可以像以前一样工作;
可重用性 - 我可以使用这些类并在其他项目中使用它们。
这似乎是最优雅的方式。如果其他人有更好的方式,我很乐意听到它。感谢大家的回复。