Page 1 of 1
The composite design pattern ?
Posted: Mon May 08, 2006 7:25 am
by Chris Corbyn
Something I was doing yesterday got me onto thinking about patterns once again.
I wrote some code that basically creates an recurisve object structure whereby the parent holds an instance of a child, which itself holds an instance of the parent.
It looked a bit nasty on first sight but after doing some research it appears that this is actually fairly common practice in other languages such as Java and C# (I even saw a few Perl implementations).
A few articles I read mentioned that the "composite pattern" is brilliant when working with such structures but the most info I've managed to find out so far is this carppy little diagram:
Code: Select all
-- Parent --
^ | |
| V V
Container Child
Does anybody know anything about this pattern and how it relates to recursive object structures?
A recursive object might come about like this:
Code: Select all
class parentClass
{
var $child;
function loadChild(&$obj)
{
$this->child =& $obj;
$this->child->loadParent(&$this);
}
}
class childClass
{
var $parent;
function loadParent(&$obj)
{
$this->parent =& $obj;
}
}
$parent =& new parentClass;
$parent->loadChild(new childClass);
print_r($parent); /* Recursion */
Posted: Mon May 08, 2006 7:39 am
by someberry
In JAVA, we were always taught that a composite pattern was this, it looks and sounds slightly different to what you thought it is. Not sure who is right
Code: Select all
+___________________+
Client -----> |Componant |
|------------------ |<-----+
|operation() : void | |
+___________________+ |
/ \ |
- |
| |
+-----------+--------+ |
| | |
+________|__________+ +___|_________< >_________________________+
|Node | |Composite |
|-------------------| |-----------------------------------------|
|operation() : void | |addComponant(comp : Componant) : void |
+___________________+ |removeComponant(comp : Componant) : void |
|operation() : void |
+_________________________________________+
Posted: Mon May 08, 2006 7:47 am
by Chris Corbyn
someberry wrote:In JAVA, we were always taught that a composite pattern was this, it looks and sounds slightly different to what you thought it is. Not sure who is right
Code: Select all
+___________________+
Client -----> |Componant |
|------------------ |<-----+
|operation() : void | |
+___________________+ |
/ \ |
- |
| |
+-----------+--------+ |
| | |
+________|__________+ +___|_________< >_________________________+
|Node | |Composite |
|-------------------| |-----------------------------------------|
|operation() : void | |addComponant(comp : Componant) : void |
+___________________+ |removeComponant(comp : Componant) : void |
|operation() : void |
+_________________________________________+
I guess your version is right... the only thing I was going on was the brief passing of that diagram. I haven't got a clue what exactly I'm looking at there

Does that actually even relate to a recursive object structure?
Ever feel like you're about 5% as clever as you thought you were?

Posted: Mon May 08, 2006 8:14 am
by someberry
d11wtq wrote:I guess your version is right... the only thing I was going on was the brief passing of that diagram. I haven't got a clue what exactly I'm looking at there

Does that actually even relate to a recursive object structure?
Ever feel like you're about 5% as clever as you thought you were?

I feel like that every time I program in JAVA.
Had a quick browse on Google for the pattern, it pulled up these two:
-
Composite Design Pattern
-
Structural Patterns - Composite Pattern
Posted: Mon May 08, 2006 2:01 pm
by Christopher
Yeah, the Composite/Component pattern is used for tree structures. It combines a few other patterns, but the trick seems to be that the parent knows just enough about the child nodes to make a useful linkage. As you probably guess the composite and component are often the same class that can be both a parent and a child.
The problem I had with the code in your original post (and you mailer auth classes

) is that the dependency goes the other direction. It can do that if it really has to, but if it doesn't then cleaner dependencies with make things more maintainable.
Posted: Mon May 08, 2006 8:46 pm
by alex.barylski
Sounds like what you've designed is an ADT (sorta)
A container class, like those found in STL (although tree isn't included it's part of the same kind of family)...
Here is my latest implementation which is part of my own whittle framework - although not entirely tested or complete it will eventually become the base class for my own DOM level 3 implementation...
Take a peak, lets compare notes...
Code: Select all
/*
NOTES:
We need this global because PHP does not support static data members and it's object
comparison '===' is not sufficient. PHP compares objects by the following method:
1) Both objects have the same attributes and values.
2) Both objects are of the same type
The problem with the above, is there are instances where two objects might have
the exact properties and values, but be instantiated in seperately, in which case
the only kind of object comparison that will work is instance comparison.
*/
$g_swiftObjectInstance_8934JKDF87923JHYUGF789; // Initialize to zero
//
// Interface and Implementation
//
class CxSwiftBase{
function addInstance()
{
global $g_swiftObjectInstance_8934JKDF87923JHYUGF789;
$this->m_objInstance = (int)$g_swiftObjectInstance_8934JKDF87923JHYUGF789++;
}
/* protected */ var $m_objInstance;
}
Code: Select all
/**
* Implements a generic tree container class.
*
* This module contains the classes required to manipulate a generic tree structure.
*
* @copyright PCSpectra Mar.16.2006
* @version 1.0.0
*/
//
// Required includes for base classes, defines, etc...
//
include_once(dirname(__FILE__).'/class.swift_base.php'); // Base class
//
// Class interface and implementation
//
class CxSwiftTree extends CxSwiftBase{
function CxSwiftTree($obj=null, $parent=null)
{
parent::addInstance();
$this->m_obj = $obj;
$this->m_arrNodes = array();
$this->m_refParent = &$parent; // NOTE: We need to assign by ref
}
function appendNode($obj)
{
$this->m_arrNodes[] = new CxSwiftTree($obj, &$this); // NOTE: We need to pass by ref
}
function removeNode()
{
$node =& $this->getParent();
$cnt = count($node->m_arrNodes);
for($i=0; $i<$cnt; $i++){
if($node->m_arrNodes[$i]->m_objInstance == $this->m_objInstance){
array_splice($node->m_arrNodes, $i, 1);
break; // Break out of loop - there shouldn't be anymore instances like this
}
}
}
function insertNode($idx, $obj, $replace=false)
{
if($replace){
$node =& $this->getNode($idx);
$node->removeNode();
$node =& $node->getParent();
$node->insertNode($idx, $obj, false);
}
else{
$arr = array_splice($this->m_arrNodes, $idx);
$this->appendNode($obj);
$this->m_arrNodes =& array_merge($this->m_arrNodes, $arr);
}
}
//
// Trivial inline accessors
function &getParent(){ return $this->m_refParent; } /* const */
function &getData(){ return $this->m_obj; } /* const */
function &getNode($idx){ return $this->m_arrNodes[$idx]; } /* const */
function &childNodes(){ return $this->m_arrNodes; } /* const */
function hasChildren(){ return (bool)count($this->m_arrNodes); } /* const */
function isLeafNode(){ return !(bool)$this->hasChildren(); } /* const */
function isRoot(){ return (bool)$this->m_refParent == null; } /* const */
//
// PRIVATE:
/* private */ var $m_obj; // Generic object container
/* private */ var $m_arrNodes; // Array of child nodes
/* private */ var $m_refParent; // Reference to parent node
/////////////////////////////////////////////////////////////////////////////////
// //
// Debug function which displays tree structure nicely - REMOVE IN RELEASE!!! //
// //
/////////////////////////////////////////////////////////////////////////////////
function dumpObject(&$root) /* static */
{
static $depth = 0;
for($y=0; $y<$depth; $y++) $spaces .= ' ';
$depth = $depth + 1;
$tmp = $root->m_arrNodes;
for($x=0; $x<count($tmp); $x++){
$obj = $tmp[$x]->m_obj;
$arr = $tmp[$x]->m_arrNodes;
$ref = $tmp[$x]->m_refParent;
echo $spaces.$obj->tag_name.'<br />';
CxSwiftTree::dumpObject($tmp[$x]);
}
$depth = $depth - 1;
}
}