line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
=head1 NAME |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
Class::Composite - Implements Composite patterns |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=head1 SYNOPSIS |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
========================= |
8
|
|
|
|
|
|
|
Collection implementation |
9
|
|
|
|
|
|
|
========================= |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
use Class::Composite; |
12
|
|
|
|
|
|
|
my $collection = Class::Composite::Container->new(); |
13
|
|
|
|
|
|
|
my $element = Class::Composite::Element->new(); |
14
|
|
|
|
|
|
|
$collection->addElement( $elem ); |
15
|
|
|
|
|
|
|
$elements = $collection->getElements(); |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
======================== |
19
|
|
|
|
|
|
|
Composite implementation |
20
|
|
|
|
|
|
|
======================== |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
package graphicBase; # Base for graphics containers and elements |
23
|
|
|
|
|
|
|
sub display { |
24
|
|
|
|
|
|
|
my $self = shift; |
25
|
|
|
|
|
|
|
foreach my $elem (@{$self->getElements()}) { |
26
|
|
|
|
|
|
|
$elem->display(); |
27
|
|
|
|
|
|
|
} |
28
|
|
|
|
|
|
|
paint($elem); |
29
|
|
|
|
|
|
|
} |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
package graphicElement; |
33
|
|
|
|
|
|
|
use base qw( Class::Composite::Element graphicBase ); |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
package graphicContainer; |
37
|
|
|
|
|
|
|
use base qw( Class::Composite::Container graphicBase ); |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
package main; |
41
|
|
|
|
|
|
|
use graphicElement; |
42
|
|
|
|
|
|
|
use graphicContainer; |
43
|
|
|
|
|
|
|
my $element = graphicElement->new(); |
44
|
|
|
|
|
|
|
my $container = graphicContainer->new(); |
45
|
|
|
|
|
|
|
$container->addElement( $element ); |
46
|
|
|
|
|
|
|
$container->display(); |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=head1 DESCRIPTION |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
C is used to provide mechanisms used by C |
51
|
|
|
|
|
|
|
and C. Class::Composite::* implements a Composite pattern (see OO Patterns books and http://www.uni-paderborn.de/cs/ag-schaefer/Lehre/Lehrveranstaltungen/Vorlesungen/Entwurfsmuster/WS0102/DPSA-IVb.pdf for example). |
52
|
|
|
|
|
|
|
A composite pattern is a collection implementation which provides same methods to the container and elements. |
53
|
|
|
|
|
|
|
The reason for using a Composite pattern is to have the same interface to deal with different objects and their containers (collections). |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
If you only need a collection implementation, then you can inherite from Class::Composite::Container and Class::Composite::Element directly. |
56
|
|
|
|
|
|
|
If you need specific method that should be applied to both your container and your elements (which is what the Class::Composite is made for), |
57
|
|
|
|
|
|
|
then you isolate the methods you want to apply on both elements and containers in a specific package. |
58
|
|
|
|
|
|
|
Then, you inherite from both your package and Class::Composite::Element for elements, and Class::Composite::Container for containers. |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
=head1 INHERITANCE |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
Class::Base |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=cut |
65
|
|
|
|
|
|
|
package Class::Composite; |
66
|
|
|
|
|
|
|
|
67
|
2
|
|
|
2
|
|
10
|
use strict; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
54
|
|
68
|
2
|
|
|
2
|
|
9
|
use warnings::register; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
191
|
|
69
|
2
|
|
|
2
|
|
8
|
use Scalar::Util qw( blessed ); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
87
|
|
70
|
|
|
|
|
|
|
|
71
|
2
|
|
|
2
|
|
8
|
use base qw( Class::Base ); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
12439
|
|
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
our $VERSION = 0.2; |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=head2 getAll() |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
Returns an array ref of all elements below, whatever their depth or type. |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=cut |
81
|
|
|
|
|
|
|
sub getAll : method { |
82
|
9
|
|
|
9
|
1
|
12
|
my $self = shift; |
83
|
9
|
|
|
|
|
11
|
my @elems = (); |
84
|
9
|
|
|
|
|
10
|
foreach my $junior ( @{$self->getElements()} ) { |
|
9
|
|
|
|
|
21
|
|
85
|
8
|
|
|
|
|
13
|
push @elems, $junior; |
86
|
8
|
50
|
|
|
|
14
|
push @elems, @{$junior->getAll} if defined($junior); |
|
8
|
|
|
|
|
23
|
|
87
|
|
|
|
|
|
|
} |
88
|
9
|
|
|
|
|
25
|
\@elems; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
=head2 getLeaves(start, end) |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
Returns all Class::Composite::Element contained in the collection, whatever their depth. |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=cut |
97
|
|
|
|
|
|
|
sub getLeaves : method { |
98
|
3
|
|
|
3
|
1
|
5
|
my ($self, $start, $last) = @_; |
99
|
3
|
|
|
|
|
4
|
my @elements = (); |
100
|
3
|
|
|
|
|
4
|
foreach my $elem ( @{$self->getElements($start, $last)} ) { |
|
3
|
|
|
|
|
8
|
|
101
|
10
|
50
|
|
|
|
25
|
defined $elem or next; |
102
|
10
|
100
|
|
|
|
29
|
if ($elem->isa('Class::Composite::Element')) { |
103
|
9
|
|
|
|
|
13
|
push @elements, $elem; |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
else { |
106
|
1
|
|
50
|
|
|
5
|
my $subElems = $elem->getLeaves() || []; |
107
|
1
|
50
|
|
|
|
9
|
push @elements, @$subElems if (@$subElems); |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
} |
110
|
3
|
|
|
|
|
13
|
\@elements; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=head2 getElements() |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
Returns the elements just below the current object. |
117
|
|
|
|
|
|
|
Returns [] |
118
|
|
|
|
|
|
|
must probably be overriden by child classes. |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
=cut |
121
|
7
|
|
|
7
|
1
|
21
|
sub getElements () : method { [] } |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=head2 getElement() |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
Returns undef |
127
|
|
|
|
|
|
|
must probably be overriden by child classes |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
=cut |
130
|
0
|
|
|
0
|
1
|
0
|
sub getElement () : method { undef } |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=head2 nOfElements() |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
Returns undef, to be overriden by child class |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
=cut |
138
|
1
|
|
|
1
|
1
|
11
|
sub nOfElements { } |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=head2 elementType() |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
Returns the class the element must belongs to, default is |
144
|
|
|
|
|
|
|
Class::Composite. |
145
|
|
|
|
|
|
|
Sets it to undef if you don't want any checking to occur. |
146
|
|
|
|
|
|
|
To be overriden in Child class. |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=cut |
149
|
11
|
|
|
11
|
1
|
44
|
sub elementType () : method { __PACKAGE__ } |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=head2 applyToAll( $sub ) |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
Applies the subroutine $sub to all elements. |
155
|
|
|
|
|
|
|
The subroutine will receive a collection element as a parameter. |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=cut |
158
|
|
|
|
|
|
|
sub applyToAll : method { |
159
|
0
|
|
|
0
|
1
|
0
|
my ($self, $sub) = @_; |
160
|
0
|
|
|
|
|
0
|
$sub->( $_ ) foreach ( @{$self->getElements} ); |
|
0
|
|
|
|
|
0
|
|
161
|
0
|
|
|
|
|
0
|
$self; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
## |
166
|
|
|
|
|
|
|
## Helper method |
167
|
|
|
|
|
|
|
## |
168
|
|
|
|
|
|
|
sub _warn { |
169
|
1
|
|
|
1
|
|
126
|
warn $_[1].' - '.caller(1)." " . caller(2) . "\n"; |
170
|
1
|
|
|
|
|
11
|
undef; |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
1; |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
__END__ |