I am working on a simple project involving Prospects and Offers. This project will integrate with a third-party mailing list provider, which will use Prospect objects to manage email addresses on the list and Offer objects to manage campaigns.
One of my concerns is that any Mailing List provider (e.g., MailChimp) may decide to stop offering their service, or change the terms in the future. Rather than make my software reliant on the provider, I want to make it reliant on a generic interface, which could be reimplemented using a different class which uses a different Mailing List provider. That way, if such a thing did happen, I would simply write a new class and instantiate in place of the old class.
This seems to be easy enough the implement. My abstract class, included below, defines abstract methods which take either Prospect or Offer objects and do generic Mailing List related functions to them, returns true/false or integer values where required. This interface should meet the needs of my application quite well.
<?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);
}
Here comes the dilemma.
In the future, the data that is passed between my application the Mailing List provider may change, however, I don't want to have to keep changing the interface everywhere. By passing objects into the methods, I can modify the methods to use new properties as they become available, without changing the interface anywhere. This seems like a very flexible solution.
But
I would like to use this class in other projects, that might not necessarily use Prospect or Offer classes. The interface above seems too tightly coupled, from the perspective of the class, in that the class is reliant on the objects being passed to it.
Does anyone have any suggestions about how I might keep the flexibilty of passing objects to the methods, but have a class that I can easily reuse for other projects?
Many thanks if you have read this far! I am always looking to improve my skills and I'll be very grateful for your insight into how I might make this better.