Singleton-Factory Hybrids FTW

Slowly but surely my framework is coming off the ground. I decided to adopt a singleton design pattern for my Cache, Template, and possibly any other engines I might have. Originally my design started as a factory, however it is now somewhat of a hybrid as there is a ::load() function that loads arbitrary classes into our singleton (rather than an instance of the same class like a proper singleton).

I wanted the system pluggable so the developer was not beholden to any particular engine, but I also needed to guarantee access to the Cache and Template objects to the models without having to either add to the $GLOBALS[] array or add to a controller’s attribute (and call like $controller->cache->…).

So I adopted a singleton design pattern, because (a) one only needs 1 cache or template object and (b) it just looks plain nice.

For example, lets look at our cache object. I modeled the interface for the cache object around the APC naming conventions since I will be using APC myself, I wanted to retain all of APC’s functionality without locking any other developers down to making sure they have APC installed.

final class Cache
{
	protected static $obj;

	public static function load( $drivername )
	{
		App::include_framework("drivers.cache/class.".strtolower($drivername).".php");

		$drivername .= "CacheEngine";

		self::$obj = new $drivername();
	}

	//Add if not exists
	public static function add( $key, $var, $life = 0 )
	{
		return self::$obj->add($key,$var,$life);
	}

	//Overwrite if exists
	public static function store( $key, $var, $life = 0 )
	{
		return self::$obj->store($key,$var,$life);
	}

	public static function fetch( $key )
	{
		return self::$obj->fetch($key);
	}

	public static function delete( $key )
	{
		return self::$obj->delete($key);
	}

	public static function clear()
	{
		return self::$obj->clear();
	}
}

Our boostrapping file (or any file where we initialize the Cache class) will have Cache::load('drivername'); statement, filling our static attribute with an instance of the proper Cache Engine, of which we have a nice pretty interface for:

interface CacheEngine
{
	//Add if not exists
	public function add( $key, $var, $life = 0 );

	//Overwrite if exists
	public function store( $key, $var, $life = 0 );

	public function fetch( $key );

	public function delete( $key );

	public function clear();
}

From here on out in our code, all we have to do to access the application’s caching ability is call say Cache::store( ... );. What this results in is a completely transparent abstraction layer allowing for drop-in replacements without having to worry about managing object instances, etc.

As for now I’m working on how I want to manage DB connections and DB abstraction. I desire the framework to be flexible and handle multiple database connections should a developer so require, or at the very least not restrain to a single connection, HOWEVER I need to make things remain easy for developers only maintaining a single connection. Obviously my Singleton-Factory hybrid will not work here.

Then comes the fun of working out the ORM aspects of the models…

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>