Given a leaf, and its parent TD, do a print:
$parent = new Node('td');
$child = new Leaf('Text:', 'Value');
$parent->add($child);
$parent->print();
print requirement:
sometimes <td>Text: Value</td>
sometimes <td>Text:</td><td>Value</td>
So far i constructed 3 solutions, but none satisfied me, i wonder which one is more OO? And is there a 4th choice?
-- Solution 1 --
// Divide the leaf object to two leaf objects
$leafText = new Leaf('Text: ');
$leafvalue = new Leaf('Value');
$parent->add($leafText);
$parent->add($leafValue);
$parent->print();
-- Solution 2 --
// Change leaf print() logic, if leaf's parent is TD, output "Text: Value",
// otherwise output "<td>Text:</td><td>Value</td>"
-- Solution 3 --
// Change parent add() logic, give leaf a variable $separate to describe if it
// should be divided
function add($child) {
if($child->separate) {
$this->parent->add($child->text);
$this->children[] = $child->value;
}
...
}
most OO would be to seperate rendering logic from data model ... your model hierarchy should be traversible by a controller, that'd render your data into a view hierarchy ...
also, "chain of control" should follow your hierarchy ... it's not up to the leaf determining its behaviour depending on the parent, it's up to the parent to get info from the leaf, and then process it depending on it's own state, or to pass necessary data to the child when querying for any sort of information ... that way the leaf is decoupled from the node ... otherwise you have a two-way dependancy, which greatly decreases reusability ...
greetz
back2dos
I'd have to go with solution 2 personally. You say that with that solution a leaf can hold a node, which you don't like, but is there any reason it has to be able to hold a node? Since you're using different classes (Node and Leaf) you should be able to add a check that prevents passing a Node into the Leaf (something like this):
class Leaf {
public function __construct($text, $value) {
if (is_object($text))
throw new Exception('error message');
if (get_class($value) == 'Node')
throw new Exception('error message');
}
}
Both of those checks should work, the second one is just checking for a specific class while the first one just prevents all objects. You could also use the is_string()
function, but that will disallow ints.