PDA

Click to See Complete Forum and Search --> : Design Patterns


tomcatexodus
Jun 14th, 2010, 11:08 AM
My previous thread started this discussion, but having refined the issue, I figured it warranted a new thread.

I'm having difficulty coming up with a logical and functional class hierarchy for a system, and I was wondering if someone could point me towards some resources where I could find more information, or provide some insight on how I could develop this.

I was interested in creating a system where I have a single Factory/Supervisor class, responsible for designating object instantiation of Widgets, as well as controlling global parameters that affect all Widget objects it instantiates.

The design restrictions/conditions I was trying to adhere to would be:
- The Factory class can not be instantiated and it's properties/methods are static. If a design concept has it functioning as an instantiated singleton, that would work fine as well.
- The Factory and only the factory needs to be responsible for global parameters (via Factory::setParam($args) or Factory::importParams($args), etc.) whereas the Widgets need only read the parameters (via Factory::getParam($args);).
- The Widgets (say 3 or more different types) cannot be explicitly instantiated outside of the creation methods of the Factory. (Example: $widget = Factory::createWidget($args); instead of $widget = new Widget($args);)
- The different Widgets would extend a BasicWidget to inherit general functionality.

My problem with this design is that I don't want to have:
- The Widgets inheriting Factory specific methods/properties such as setParams() or createWidget().
- The Widget's __construct($args) method making use of debug_backtrace() or another process intensive function to determine the calling method/class for instantiation restriction. Whatever keeps it running fastest.

My attempts thus far result in either of the "don't want" cases. It seems to me there must be an approach that satisfies these conditions. I posted something regarding this before, but I've refined the problem now, and hopefully someone can point me in the right direction.

kows
Jun 14th, 2010, 12:10 PM
there is no way to do this properly without using debug_backtrace() (I don't consider class inheritance a proper way of doing this). using debug_backtrace() might be a bit of a hack, but it does get you where you want to be. and it's the only thing that PHP offers as of right now as a way to get what you want. if you must have such restrictions, then you might just have to bite the bullet.

penagate
Jun 14th, 2010, 09:06 PM
I think you might be thinking too much about the pattern, rather than the design. You've listed some requirements but not the reasons for them. They are the requirements of a design rather than the true requirements of the system.

What is the need for a factory class? Why not have some static members in the Widget class? You can mark it as abstract if you need to require that only particular types of widgets are instatiated. Static members won't be inherited by widget instances.

I prefer to avoid using words like Factory and Widget because they move the discussion into academic territory. Forget about design patterns and think about what comes naturally for the particular system you're building.

tomcatexodus
Jun 14th, 2010, 09:41 PM
After considerable thought away from the screen, I've concluded you're both right. I've focused too much on the semantics of something (despite it's at times beneficial effect towards the desired results) rather than the application of it.

Thank you penagatefor your to-the-point evaluation of my problem.

Many a thanks kowsfor your continued help in this and the other thread.

I'll post a finished draft of the script with manual when complete.

tomcatexodus
Jun 15th, 2010, 09:51 AM
Ok, I've changed my approach entirely, but now have another question of design choices.


class Widget{
protected $widgets = array(); //contains other widgets
}


Would the best design approach be to have the constructor take an argument that is the parent widget? (This is what I'm doing now)

Eg:


class Widget{
protected $widgets = array(); //contains other widgets
public __construct($args, $parentWidget = NULL){
if(!is_null($parentWidget)){
$parentWidget->widgets[] = &$this;
}
.
.
.
}
}

$parentWidget = new Widget($args);
$childWidget = new Widget($args, $parenWidget);


Or should the widgets be responsible for creating the children widgets themselves?

Eg:


class Widget{
protected $widgets = array(); //contains other widgets
public __construct($args){
.
.
.
}
public newWidget($args){
$newWidget = new Widget($args);
$this->widgets[] = &$newWidget;
return $newWidget;
}
}

$parentWidget = new Widget($args);
$childWidget = $parentWidget->newWidget($args);



Which is considered a better design approach?

kows
Jun 15th, 2010, 10:35 AM
I like something similar to the way the DOM works:
$parent = new MyObject;
$child = new MyOtherObject;

$parent->addChild($child);
but if you couldn't do this, then I like the former more than the latter.

tomcatexodus
Jun 15th, 2010, 10:40 AM
The DOM approach was brought to my attention already, but I don't think it would fit, as the only time parent/child definition needs to be performed is during the instantiation of a child. Allowing post-instantiation parent/child definition could encourage unintended use.

So you feel that explicitly defining the parent by argument is better than implicitly by the object calling the create method?

kows
Jun 15th, 2010, 11:28 AM
either way, you're getting the same result. I don't really like either of your solutions or think either is explicitly better than the other. with that said, I generally like direct instantiation over indirect, unless there's some reason or benefit for you to use indirect instantiation.

now that I've looked at it more, maybe I do prefer the alternative (using a "new" method within the parent), because I don't really want to have to pass the parent object into the constructor every time I want to add a child.

also, if being able to add a child later on would break something (after changing settings or performing some action or whatever), then you could always make a flag either in the parent or child that either doesn't let any children to be added to the parent, or won't let the child be added to anything.