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 comment