Subtype Polymorphism – Swapping Implementation at Runtime

Alejandro Gervasio
Share

How many people doubt the relevance of Inheritance and Polymorphism in Object-Oriented design? Probably very few, most likely because of ignorance or a narrow mindset. But there is one small gotcha here that can’t be easily overlooked. While understanding the logic that pulls on the reins of Inheritance is straightforward, things are more difficult when it comes to digging deep into the nuts and bolts of Polymorphism.

The term Polymorphism is intimidating in its own right, and its academic definition is plagued with several disparate slants which make it even harder to understand what’s actually under its hood. Peripheral concepts such as Parametric Polymorphism and ad-hoc Polymorphism, usually implemented through method overriding/overloading, do have prolific niches in some programming languages, but the last instance should be dropped when it comes to designing extensible systems capable of consuming specific contracts (read abstractions) without having to check if the implementers belong to an expected type.

In short, most of the time any generic reference made to Polymorphism in OOP is implicitly assumed as the ability exposed by a system for defining a set of contracts or interfaces which in turn are honored by different implementations. This kind of “canonical” Polymorphism is commonly known as subtype Polymorphism, as the implementers of the interfaces are considered subtypes of them regardless if there’s an actual hierarchy down the line or not.

As one might expect, understanding the nature of Polymorphism is only half of the learning process; the other half is, of course, demonstrating how to design polymorphic systems that can be accommodated to work in pretty realistic situations, without getting caught in the trap of showcasing just “some nifty didactical code” (in many cases a cheap euphemism for toy code).

In this article I’ll show you how to exploit the virtues that Polymorphism offers through the development of a pluggable cache component. The core functionality can be expanded later to suit your needs through the development of additional cache drivers.

Defining the Component’s Interfaces and Implementations

The menu of available options to choose from when building an extensible caching component is anything but scarce (if you’re skeptical, just peek behind the curtain of some popular frameworks). In this case in particular, though, the component I present here has the nifty ability to swap out different cache drivers at runtime, all without having to amend a single chunk of client code.

So how do we get this going without sweating too much during the development process? Well, the first logical step to take would be …yep, define a segregated cache contract which will be agreed to later by distinct implementations, hence taking advantage of the benefits of Polymorphism.

At its most basic level, the aforementioned contract looks like this:

<?php
namespace LibraryCache;

interface CacheInterface
{
    public function set($id, $data);
    public function get($id);
    public function delete($id);
    public function exists($id);
}

The CacheInterface interface is a skeletal contract that abstracts the behavior of a generic caching element. With the interface in place, it’s easy to create a few concrete cache implementations that adheres to the its contract.

Since I want to keep things concise and easy to assimilate, the cache drivers I set up will be just a skinny duet: the first one uses the file system as the underlying backend for caching/fetching data, while the second one employs the APC extension behind the scenes.

Here’s the file-based cache implementation:

<?php
namespace LibraryCache;

class FileCache implements CacheInterface
{
    const DEFAULT_CACHE_DIRECTORY = 'Cache/';
    private $cacheDir;

    public function __construct($cacheDir = self::DEFAULT_CACHE_DIRECTORY) {
        $this->setCacheDir($cacheDir);
    }
    
    public function setCacheDir($cacheDir) {
        if (!is_dir($cacheDir)) {
            if (!mkdir($cacheDir, 0644)) {
                throw InvalidArgumentException('The cache directory is invalid.');
            }
        }
        $this->cacheDir = $cacheDir;
        return $this;
    }
    
    public function set($id, $data) {
        if (!file_put_contents($this->cacheDir . $id, serialize($data), LOCK_EX)) {
            throw new RuntimeException("Unable to cache the data with ID '$id'.");
        }
        return $this;
    }
    
    public function get($id) {
        if (!$data = unserialize(@file_get_contents($this->cacheDir . $id, false))) {
            throw new RuntimeException("Unable to get the data with ID '$id'.");
        }
        return $data;
    }
    
    public function delete($id) {
        if (!@unlink($this->cacheDir . $id)) {
            throw new RuntimeException("Unable to delete the data with ID '$id'.");
        }
        return $this;
    }
    
    public function exists($id) {
        return file_exists($this->cacheDir . $id);
    }
}

The driving logic of the FileCache class should be easy to understand. By far the most relevant thing here is that it exposes a neat polymorphic behavior as it’s a faithful implementer of the earlier CacheInterface.

Although this ability is sweet and charming, on its own it’s not precisely something I’d sing praise about considering that the goal here is to create a cache component capable of switching back-ends at runtime. Let’s make an extra effort on behalf of an instructive cause and bring to life yet another slim implementer of the CacheInterface.

The implementation below adheres to the interface’s contract, but this time by consuming methods bundled with the APC extension:

<?php
namespace LibraryCache;

class ApcCache implements CacheInterface
{
    public function set($id, $data, $lifeTime = 0) {
        if (!apc_store($id, $data, (int) $lifeTime)) {
            throw new RuntimeException("Unable to cache the data with ID '$id'.");
        }
    }
    
    public function get($id) {
        if (!$data = apc_fetch($id)) {
            throw new RuntimeException("Unable to get the data with ID '$id'.");
        } 
        return $data;
    }
    
    public function delete($id) {
        if (!apc_delete($id)) {
            throw new RuntimeException("Unable to delete the data with ID '$id'.");
        }
    }
    
    public function exists($id) {
        return apc_exists($id);
    }
}

The ApcCache class isn’t the flashiest APC wrapper you’ll see in your career, it packages all the functionality required for saving, retrieving, and removing data from memory.

Let’s pat ourselves on the back as we’ve managed to implement a lightweight cache module whose concrete back-ends not only can be swapped out easily at runtime thanks to their polymorphic nature, but adding a few more down the road is ridiculously simple. Just write another implementation that adheres to the CacheInterface.

I should stress however that actual subtype Polymorphism has been achieved by implementing a contract defined through an interface construct, which is a pretty ubiquitous approach. Nothing should stop you, however, from being less orthodox and getting the same results by switching over an interface declared as a set of abstract methods pitched inside an abstract class. If you’re feeling adventurous and want to walk that sideways path, the contract and the corresponding implementations could be refactored as follows:

<?php
namespace LibraryCache;

abstract class AbstractCache
{
    abstract public function set($id, $data);
    abstract public function get($id);
    abstract public function delete($id);
    abstract public function exists($id);
}
<?php
namespace LibraryCache;

class FileCache extends AbstractCache
{
	// the same implementation goes here
}
<?php
namespace LibraryCache;

class ApcCache extends AbstractCache
{
	// the same implementation goes here 
}

From top to bottom, this is true a polymorphic approach that fights head to head with the one discussed before. Personally, and this is nothing but speaking for myself, I prefer to use interface constructs for defining contracts and appeal to abstract classes only when it comes to encapsulating a boilerplate implementation shared by a few subtypes. It’s up to you to pick the methodology that will best fit your needs.

At this point I could drop the curtain write some fancy closing comments, babbling on about our impressive coding skills and bragging about the flexibility of or cache component, but that would be plain a disservice. Polymorphism exposes its most seductive facet when there exists some client code capable of consuming several implementations without checking if they’re types of something as long as they adhere to an expected contract. So, let’s unveil that facet by hooking up the cache component to a basic client view class, something that will permit us do some neat HTML caching without much fuss.

Putting the Cache Drivers to Work

Caching HTML output through our sample cache module is so banal, that I’ll save any verbose explanation for some other time. The whole caching process can be reduced to a naïve view class, similar to this one:

<?php
namespace LibraryView;

interface ViewInterface
{
    public function setTemplate($template);
    public function __set($field, $value);
    public function __get($field);
    public function render();
}
<?php
namespace LibraryView;
use LibraryCacheCacheInterface;

class View implements ViewInterface
{
    const DEFAULT_TEMPLATE = 'default';    
    private $template;
    private $fields = array();
    private $cache;

    public function __construct(CacheInterface $cache, $template = self::DEFAULT_TEMPLATE) {
        $this->cache = $cache;
        $this->setTemplate($template);
    }
    
    public function setTemplate($template) {
        $template = $template . '.php';
        if (!is_file($template) || !is_readable($template)) {
            throw new InvalidArgumentException(
                "The template '$template' is invalid.");   
        }
        $this->template = $template;
        return $this;
    }
    
    public function __set($name, $value) {
        $this->fields[$name] = $value;
        return $this;
    }
    
    public function __get($name) {
        if (!isset($this->fields[$name])) {
            throw new InvalidArgumentException(
                "Unable to get the field '$field'.");
        }
        return $this->fields[$name];
    }
    
    public function render() {
        try {
            if (!$this->cache->exists($this->template)) {
                extract($this->fields);
                ob_start();
                include $this->template;
                $this->cache->set($this->template, ob_get_clean());
            }
            return $this->cache->get($this->template);
        }
        catch (RuntimeException $e) {
            throw new Exception($e->getMessage());
        } 
    }
}

The flashiest kid on the block is the class’ constructor, which consumes an implementer of the earlier CacheInterface, and the render() method. Since the responsibility of this last one is caching the view’s template once it’s been pushed through the output buffer, it’d be pretty nice to exploit this ability and cache an entire HTML document.

Let’s say the view’s default template has the following structure:

<!doctype html>
<html>
 <head>
  <meta charset="utf-8">
  <title>The Default Template</title>
 </head>
 <body>
  <header>
   <h1>You are viewing the default page!</h1>
<?php echo $this->header;?>
  </header>
  <section>
<?php echo $this->body;?>
  </section>
  <footer>
<?php echo $this->footer;?>
  </footer>
 </body>
</html>

Now, let’s have some fun and cache the document by feeding the view with an instance of the ApcCache class:

<?php
use LibraryLoaderAutoloader,
    LibraryCacheFileCache,
    LibraryCacheApcCache,
    LibraryViewView;
        
require_once __DIR__ . '/Library/Loader/Autoloader.php';
$autoloader = new Autoloader;
$autoloader->register();

$view = new View(new ApcCache());

$view->header = 'This is my fancy header section';
$view->body = 'This is my fancy body section';
$view->footer = 'This is my fancy footer section';

echo $view->render();

Pretty nice, right? But hang on just a moment! I got so caught up in the moment that I forgot to mention the above snippet will blow up on any system where the APC extension hasn’t been installed (naughty sysadmins!). Does that mean that the beautifully-crafted cache module isn’t reusable anymore?

Here’s precisely where the file-based driver comes to the rescue, which can be dropped into client code without getting a single compliant from it:

<?php
$view = new View(new FileCache());

The above one-liner explicitly declares that the view will be caching its output using the file system instead of shared memory. This switching of cache back-ends on the fly shows in a nutshell why Polymorphism is so crucial when it comes to designing highly-decoupled modules. It allows us to easily rewire things at runtime without rippling fragility/rigidity-related artifacts to other parts of our system.

Closing Remarks

Crushed under a overwhelming pile of formal definitions that make understanding the concept elusive, Polymorphism is really one of those beautiful things in life which, once you do understand it, makes you wonder how you could have gone on for so long without it.

Polymorphic systems are by nature much more orthogonal, easier to extend, and a lot less vulnerable to infringing central paradigms such as the Open/Closed Principle and the wise “Programming to Interfaces” mantra. Although rather primitive, our cache module is a shining example of these virtues in action.

If you haven’t refactored your applications yet so that they can take advantage of the benefits brought to the table by Polymorphism, you’d better hurry up because you’re missing the jackpot!

Image via Fotolia