I have a system that allows certain functionality to be implemented different ways, but requires that the functionality of each implementing class be wrapped in another layer. For example, each implementor has a doFoo
method that interacts with an API. The implementor classes can be loaded at runtime (they are, essentially, plugins for hooking into different APIs), and thus the set of possible implementors is not fixed and cannot simply be handled by a switch
or an enum-like structure.
But each time one of the implementor classes executes its doFoo
method, I also need to ensure that additional, method-specific code occurs before and after (think system-wide logging, error-handling, and input and output sanity-checking that are the same for all implementors).
I have the following basic setup:
- an interface,
FooInterface
- an abstract class
FooAbstract
that implementsFooInterface
and sets up some default actions. - a concrete class
Foo
that extendsFooAbstract
.Foo
serves as a kind of factory/bridge class that instantiates an implementor and adds its own code when calling any of the implementor's methods - concrete classes
FooImplementorABC
,FooImplementorXYZ
, etc., each of which extendsFooAbstract
.
That way, when a user wants to use the ABC
implementation of FooInterface
, the user calls new Foo('ABC')
. The Foo
constructor instantiates the right implementor and the implementor's code as necessary.
Example code (sample code only; the real classes are more complex and are all broken into files and autoloaded appropriately):
<?php
interface FooInterface
{
public function doFoo();
public function doBar();
public function doGenericThing();
}
abstract class FooAbstract implements FooInterface
{
abstract public function doFoo();
abstract public function doBar();
public function doGenericThing()
{
echo "Doing something generic\n";
}
}
class Foo extends FooAbstract
{
/** @var FooAbstract */
private $implementor;
/**
* The constructor for this class accepts an implementation name.
* It then attempts to instantiate the appropriate implementor
* class.
*
* @param $implementationName String
*/
public function __construct($implementationName)
{
$implementorClassName = 'FooImplementor' . $implementationName;
try {
if (class_exists($implementorClassName)) {
$this->implementor = new $implementorClassName(); // Yes, this works in PHP! One of its best or worst features, depending on your perspective.
} else {
throw new Exception("ERROR: No implementation for $implementationName found!");
}
} catch (Exception $e) {
echo "\n\n{$e->getMessage()}\n\n";
}
}
public function doFoo()
{
echo "Doing Foo\n";
// Do some stuff
$this->implementor->doFoo();
// Do some stuff
echo "Done with Foo\n\n";
}
public function doBar()
{
echo "Doing Bar\n";
// Do some stuff
$this->implementor->doBar();
// Do some stuff
echo "Done with Bar\n\n";
}
}
class FooImplementorABC extends FooAbstract
{
public function doFoo()
{
echo "Foo Implementor ABC just did Foo!\n";
}
public function doBar()
{
echo "Foo Implementor ABC just did Bar!\n";
}
}
class FooImplementorXYZ extends FooAbstract
{
public function doFoo()
{
echo "Foo Implementor XYZ just did Foo!\n";
}
public function doBar()
{
echo "Foo Implementor XYZ just did Bar!\n";
}
}
$myFooABC = new Foo('ABC');
$myFooXYZ = new Foo('XYZ');
$myFooABC->doFoo();
$myFooXYZ->doFoo();
$myFooABC->doBar();
$myFooXYZ->doBar();
$myFooQRS = new Foo('QRS'); // displays an error message
All of this works just fine; the methods all get wrapped correctly, the implementation details are unimportant to the consumer, etc.
My questions are:
- Is this a pattern or an anti-pattern?
- If it's a pattern, is there a name for it? I can't figure out what it would be. It seems to me like a hybrid of the factory, bridge, and decorator patterns.
- If it's an anti-pattern, why? How is this going to bite me down the road?
else
clause ? (thus, removing thetry...catch
structure) – Spotted Oct 16 '15 at 13:51