The other definition is to compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
When: Any time there is partial overlap in the capabilities of objects.
Objects may be members of a number of linked lists in our system. The linked lists organize the objects by different criteria.
package LinkedList; use ImplictThis; ImplicitThis::imply();
sub new { my $type = shift; bless { next=>, previous=> }, $type; }
sub next { return $next; } sub set_next { $next = shift; return 1; } sub previous { return $previous; } sub set_previous { $previous = shift; return 1; } sub append { my $ob = shift; $ob->isa(__PACKAGE__) or die; $next or do { $next = $ob; $ob->set_previous($this); return 1; } $ob->set_next($next); $next->set_previous($ob); $ob->set_previous($this); $this->set_next($ob); return 1; }
We can inherit this, but inheriting it multiple times doesn't do us any good: we only ever have one instance of the LinkedList this way - ourselves. Using composition gives us what we want:
package TriceQueuedObject; use LinkedList; use ImplicitThis; ImplicitThis::imply();
sub new { my $type = shift; my $me = { sort_order => new LinkedList, size_order => new LinkedList, save_order => new LinkedList, @_ }; bless $me, $type; }
# create accessors that defer the action to each object, for each object composing us: # method A: see text below
sub next_sort { return $sort_order->next(); } sub previous_sort { return $sort_order->previous(); } sub set_next_sort { return $sort_order->set_next(@_); } sub append_sort { return $sort_order->append(@_); }
sub next_size { return $size_order->next(); } sub previous_size { return $size_order->previous(); } sub set_next_size { return $size_order->set_next(@_); } sub append_size { return $size_order->append(@_); }
sub next_save { return $save_order->next(); } sub previous_save { return $save_order->previous(); } sub set_next_save { return $save_order->set_next(@_); } sub append_save { return $save_order->append(@_); }
# directly return references to objects that compose us: # method B: see text below
sub get_sort_order { return $sort_order; } sub get_size_order { return $size_order; } sub get_save_order { return $save_order; }
Where it says "method A" and "method B" illustrate two very different approaches to giving users of our object access to the our parts. "Method A" creates all new accessors which do their work by calling accessors in the composing objects. "Method B" simply returns the composing objects and lets the user call the methods directly. For example:
# using method A:
$ob->next_sort($ob2);
# using method B:
$ob->get_sort_order()->set_next($ob2);
Which is better? Well, it depends. If your object is merely a container for other objects, B makes more sense. If your object is a Facade, providing a new interface to several objects, A makes more sense. If you consider the objects you contain to be implementation dependent, and you don't want to have to support returning intermediate objects in the future, A lets you hide your implementation better. B makes for shorter code and less typing when the relationship between the objects isn't likely to change.
Each LinkedList instance is a "delegate" in this example. The methods that propogate requests to them are "delegate methods".
Compose means a special thing: it refers to building objects using DelegationConcept. Delegation-composition hangs onto constituent parts using references. By contrast, MixIns inherit from each part. MixIns prevent returning a WholeObject in responce to requests for information, and they prevent you from having a more than one of any given part.
The article is originally from Perl Design Patterns Book
Search Encyclopedia
|
Featured Article
|