Special Factory Design Pattern...

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
tomcatexodus
Forum Newbie
Posts: 9
Joined: Thu Apr 08, 2010 9:42 pm

Special Factory Design Pattern...

Post by tomcatexodus »

I'm currently writing (rather, have written) a set of classes, that make use of various design pattern principles, but I have a problem.

I'm trying to create a singleton factory class, that instantiates objects that cannot otherwise be instantiated. In other words, the Widgets extend from the Factory class, and have a protected __construct(). The problem is that my Widgets are obviously then inheriting many Factory specific methods I do not want them to possess, such as the creation methods themselves.

Here's an example:

Code: Select all

abstract class Factory{
    protected static $params = array(); //these are parameters that would be used by widgets at runtime, but are set by and stored in the Factory class
    public static function createWidget($args){
        return new Widget($args);
    }
    public static function setParam($args1, $args2){ //should also be invisible to the Widget class, as Widgets shouldn't be able to set params, only read them
        self::$params[$args1] = $args2;
    }
}

class Widget extends Factory{
    protected function __construct($args){
        //do constructor stuff
    }
}

$myFailFactory = new Factory(); //fails of course, as it should
$myFailWidget = new Widget("foo"); //fails like it should as well
$myGoodWidget = Factory::createWidget("bar"); //success
The problem is though, now I can do the following:

Code: Select all

$myFailWidget = Widget::createWidget("Yikes"); //succeeds of course, but I don't want it to!
$myFailWidget->setParam("foo", "bar");
Are there any design pattern principles that I should read about that could help rectify this? Is there a common approach taken to limit the inheritance of certain properties/methods?
User avatar
requinix
Spammer :|
Posts: 6617
Joined: Wed Oct 15, 2008 2:35 am
Location: WA, USA

Re: Special Factory Design Pattern...

Post by requinix »

A singleton factory doesn't make sense. Being a singleton means that there is a finite number of these things floating around - often just one. Wrapping a factory around it means you can create as many singletons as you want. And now they're not singletons.

The real world to the rescue:
Would you consider a car to "inherit from" the factory that created it? If a factory has operating hours then does a car have them too?
tomcatexodus
Forum Newbie
Posts: 9
Joined: Thu Apr 08, 2010 9:42 pm

Re: Special Factory Design Pattern...

Post by tomcatexodus »

I understand the seemingly misplaced logic on my behalf here.

The reason Widgets are inheriting from the Factory are for visibility. The Widget constructor is protected so that only the Factory may access it.

I have read in many places (although I have not done the speed tests myself) that using functions like debug_backtrace() to find the calling class, for the purpose of restricting instantiation to certain methods, is very inefficient.

This example only outlines a single property I want both the Factory and Widgets, being the static $params in Factory. There are many more properties and methods that both should have access to, but also several that I'd like to restrict inheritance of, such as createWidget() to only the Factory.

Anyways, if you (or anyone else) has any insight they wish to share on how I could restructure this design to achieve what I'm looking to, I'm all ears :)
User avatar
requinix
Spammer :|
Posts: 6617
Joined: Wed Oct 15, 2008 2:35 am
Location: WA, USA

Re: Special Factory Design Pattern...

Post by requinix »

Question:

Any reason the factory method has to be implemented in a separate class?
tomcatexodus
Forum Newbie
Posts: 9
Joined: Thu Apr 08, 2010 9:42 pm

Re: Special Factory Design Pattern...

Post by tomcatexodus »

Well... I'll explain the intended functionality, that way we can figure out if my approach is entirely flawed, or otherwise:

There are several types of Widgets, and they each share some properties/methods, so let's say:

Code: Select all

abstract class WidgetBase{
    protected $myProperty1;
    protected $myProperty2;
    protected function myMethod(){ ... }
}

class Widget1 extends WidgetBase{
    protected $myProperty3;
    protected function __construct($args){ ... }
}

class Widget2 extends WidgetBase{
    protected $myProperty4;
    protected function __construct($args){ ... }
}
The __construct() is protected to prevent normal instantiation. I want a Factory class to oversee the instantiation of the Widget objects, so that when 'global' parameters are set in the Factory, they can be shared with the Widgets. So:

Code: Select all

abstract class Factory{
    protected static $params = array();
    public static function createWidget1($args){
        return new Widget1($args);
    }
    public static function createWidget2($args){
        return new Widget2($args);
    }
}
abstract class WidgetBase extends Factory{
    protected $myProperty1;
    protected $myProperty2;
    protected function myMethod(){ ... }
}
.
.
.
So far as I could tell, using a Factory class to manage object instantiation as well as global parameters for the objects, was the cleanest and fastest route. Using tons of backtraces and whatnot to restrict Widget creation to certain methods/classes is pretty heavy lifting, and I'm trying to keep this as fast as possible of course.

Nothing is in stone, so I can change the entire class hierarchy.
Post Reply