3

I'm trying to decide the design of a system which is meant to allow for a high amount of extensiblity. From what I can tell, a pattern such as the abstract factory would not allow for overriding of the base methods, apart from duplicating code (as demonstrated below).

I've done some preliminary research into aspect oriented programming and it seems to be along the lines of what I'm looking for but I'm having a difficult time wrapping my head around the specifics.

abstract class Object {

    protected $object_id;
    protected $name;

    function LoadObjectData()
    {
        $file_contents = readfile('object'.$object_id.'.data');
        $data = array();
        // parse file contents into $data array...
        return $data;
    }

    function Create()
    {
        $data = $this->LoadObjectData();
        $name = $data['name'];
        return $data;
    }

}

class User extends Object {

    protected $email_address;

    function Create()
    {
        $data = parent::Create();
        $this->email_address = $data['email_address'];
        return $data;
    }

}

//----------Module 1-MySQL Lookup-------------
/*
 * Redefine Object::LoadObjectData() as follows:
*/

function LoadObjectData()
{
    $data = array();
    $result = mysql_query("SELECT...");
    // construct array from result set
    return $data;
}

//----------Module 2-Cache Machine-------------
/*
 * Redefine Object::LoadObjectData() as follows:
 */

function LoadObjectData()
{
    if (exists_in_cache($object_id)) {
        return get_cached_object($object_id);
    }
    $data = parent::LoadObjectData();
    cache_object($object_id, $data);
    return $data;
}

(This is sort of a poor example, but hopefully it helps to get my point across)

The intended system would have a very large proportion of methods available to be extended and I would like to minimize the extra effort and learning necessary for developers.

Is AOP exactly what I'm looking for, or is there a better way to deal with this?

Thanks!

hakre
  • 193,403
  • 52
  • 435
  • 836
Godwin
  • 9,739
  • 6
  • 40
  • 58

2 Answers2

1

So, you want to use a decorator pattern without defining the decorator itself.

If yes, then it's a monkeypatching and can be done with aspect-oriented tools. This can be solved easily with following extensions and frameworks:

  1. PHP Runkit Extension
  2. Go! Aspect-Oriented framework for PHP
  3. PHP-AOP Extension.
lisachenko
  • 5,952
  • 3
  • 31
  • 51
-1

You don't have to declare the base class as an abstract class. You can make it a regular class and have it load and instantiate other classes based on passed construct parameters. The constructor can return an instance of a class, not just the class the constructor is in. To avoid duplicating code, you can mix static with instantiated functions and variables. Just remember that a static function or variable is the same for ALL instances. Change a static variable in one and it is changed for all instances. A rather basic example of a plugin architecture.

class BaseObject {
    protected static $cache = array();

    public function __construct($load_plugin) {
        require_once($load_plugin.'.class.php');
        $object  = new $load_plugin();
        return $object;
    }

    public static function cacheData($cache_key, $data) {
        self::$cache[$cache_key] = $data;
    }
}

class Plugin extends BaseObject {
    public function __construct() {
    }

    public function loadData() {
        // Check the cache first
        if ( !isset(self::$cache[$cache_key]) ) {
            // Load the data into cache
            $data = 'data to cache';
            self::cacheData($cache_key, $data);
        }
        return self::$cache[$cache_key];
     }
}
Brent Baisley
  • 12,641
  • 2
  • 26
  • 39
  • In this example, the intention to cache nor the intention to load from a database is by design. However we assume that another developer has developed modules (Module 1 and Module 2) in order to modify the original program flow. Yes, in reality a well designed application will include a native cache, however this is just an example. Your method is interesting but doesn't allow for multiple extensions nor does it answer the question relating to existing design patterns. Thanks though. – Godwin Jan 14 '12 at 03:25
  • It allows for unlimited extensions. Just pass the name of the extension to load and the base class will load it, create an instance of it and return the instance. A design like this allows all the extensions/plugins to be managed by the base class (factory), forcing all extensions to be singletons if needed. The plugins could overload any methods in the base class, which would modify the behavior of the base class. – Brent Baisley Jan 14 '12 at 23:31