[56K WARN] difference between composites and decorators?

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
User avatar
raghavan20
DevNet Resident
Posts: 1451
Joined: Sat Jun 11, 2005 6:57 am
Location: London, UK
Contact:

[56K WARN] difference between composites and decorators?

Post by raghavan20 »

I see in composite pattern, one object tries to compose one or more of the same type and when i compared the uml diagram for decorator pattern from heads first design patterns with uml diagram for composite pattern from wikipedia.org they both look the same although i was never able to understand the decorator pattern properly.

Any light shed on this area should be very helpful for me and others. thanks.
jmut
Forum Regular
Posts: 945
Joined: Tue Jul 05, 2005 3:54 am
Location: Sofia, Bulgaria
Contact:

Post by jmut »

Could you give us links to UML diagramms you refer.
From what I see in wikipedia...there are not the same.
User avatar
raghavan20
DevNet Resident
Posts: 1451
Joined: Sat Jun 11, 2005 6:57 am
Location: London, UK
Contact:

Post by raghavan20 »

jmut wrote:Could you give us links to UML diagramms you refer.
From what I see in wikipedia...there are not the same.
Decorator from Heads first design patterns
Image


Composite from Wikipedia.org
Image
User avatar
johno
Forum Commoner
Posts: 36
Joined: Fri May 05, 2006 6:54 am
Location: Bratislava/Slovakia
Contact:

Post by johno »

Decorator is used when you want to change behaviour of some class. For example

Code: Select all

abstract class UserFinder {
    abstract public function findUserByFirstName($name);
}

class MySqlUserFinder extends UserFinder {
     public function findUserByFirstName($name) {
        // do select and return array of Users with name $name
     }
}

// decorator
class UserFinderCache extends UserFinder {
    private $originalFinder;
    private $cachedResult;

    public function __construct($finder) {
        $this->originalFinder = $finder;
        $this->cachedResult = false;
    }

    public function findUserByFirstName($name) {
         if($this->cachedResult === false) {
              $this->cachedResult = $this->originalFinder->findUserByFirstName($name);
         }
         return $this->cachedResult;
     }
} 

// basic usage
$finder = new MySQLUserFinder();
$finder->findUserByFirstName('John'); // first call to DB
$finder->findUserByFirstName('John'); // second call to DB

// decorator usage

$finder2 = new UserFinderCache($finder);
$finder->findUserByFirstName('John'); // first call to DB
$finder->findUserByFirstName('John'); // no call to DB, result from cachedResult

Composite patter isn something like a tree folder/file like structure.

Code: Select all

// component
abstract class Item {
   abstract public function delete();
}

// leaf
class File extends Item {
    private $file;

    public function delete() {
          @unlink($this->file);
    }
}

// composite
class Folder extends Item {
    private $items = array();

    public function delete() {
         foreach($this->items as $item) $item->delete();
    }

    public function addItem($item) {
         $this->items[] = $item;
    }
}

// usage
$root = new Folder();
$file1 = new File('afile.txt');
$root->addItem($file1);



$folder = new Folder();
$file2 = new File('afile2.txt');
$folder->addItem($file2);

$root->addItem($folder);

$root->delete(); // deletes all recursively
Got it?
User avatar
raghavan20
DevNet Resident
Posts: 1451
Joined: Sat Jun 11, 2005 6:57 am
Location: London, UK
Contact:

Post by raghavan20 »

thanks for your examples johno.

i guess decorator works like this:
we have one concrete object which we pass to a decorator which adds a new functionality to the passed object and this whole new object after decorated can be passed to another decorator to add other functionality and so forth.

the composite pattern is very clear from the example. but apart from the file example, where else do you think it can be implemented?
User avatar
johno
Forum Commoner
Posts: 36
Joined: Fri May 05, 2006 6:54 am
Location: Bratislava/Slovakia
Contact:

Post by johno »

raghavan20 wrote:i guess decorator works like this:
we have one concrete object which we pass to a decorator which adds a new functionality to the passed object and this whole new object after decorated can be passed to another decorator to add other functionality and so forth.
Yes, it can be done. Adding and/or modifying behavior on the fly thats decorator.
raghavan20 wrote:the composite pattern is very clear from the example. but apart from the file example, where else do you think it can be implemented?
Composite pattern is very useful for any tree hierarchies. Everywhere you have parent-child ralationship you can use composite. Nested categorization, page structure, XML, ... this list is endless.
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post by Ollie Saunders »

In my library is use composite so that fieldsets can store other fieldset or fields (although I call them containers and widgets). I've had a tricky time getting my head round the usefulness of the decorator pattern myself. Here are a couple of important conclusions I've come to about the decorator
  • Decoration is not an alternative to inheritance, in that you can't use it everywhere where you can use inheritance. Decoration is actually quite limiting because you can really talk to the object you are decorating. All you can do it just stick stuff on the top of it.
  • You should not use __call() and friends to make superclass decorators that can decorate any object. I read a blog post where the author listed about 4 good reasons why this is. Unfortunately I can neither find the post nor remember the points now except for the fact that you can't use reflection on a __call() implemented decorator. and thus...
  • Decorator classes that just delegate every method call on to the object being decorated, despite the duplication, are not a design smell. Although this view comes very unnaturally to me.
  • Where you can achieve something through decoration, i.e. you are just tacking on new stuff and not interfacing with the parent, you probably should use decoration because it allows you to extend that decoration separately from the object being decorated or possibly decorate a couple of similar objects with one decorator....in short you get a lot more flexibly of extension. Not needing to change something at runtime is not a good enough excuse to ignore decorators.
Post Reply