Commit | Line | Data |
ef45e915 |
1 | =pod |
2 | |
3 | =head1 NAME |
4 | |
5 | Moose::Manual::Roles - Roles, an Alternative to Deep Hierarchies and Base Classes |
6 | |
7 | =head1 WHAT IS A ROLE? |
8 | |
9 | A role is something that classes do. Usually, a role encapsulates some |
10 | piece of behavior or state that can be shared between classes. It is |
11 | important to understand that I<roles are not classes>. Roles do not |
12 | participate in inheritance, and a role cannot be instantiated. |
13 | |
14 | Instead, a role is I<composed> into a class. In practical terms, this |
15 | means that all of the methods and attributes defined in a role are |
16 | added directly to (we sometimes say ("flattened into") the class that |
17 | consumes the role. These attributes and methods then show up in the |
18 | class as if they were defined directly in the class. |
19 | |
20 | Moose roles are similar to mixins or interfaces in other languages. |
21 | |
22 | Besides defining their own methods and attributes, roles can also |
23 | require that the consuming class define certain methods of its |
24 | own. You could have a role that consisted only of a list of required |
25 | methods, in which case the role would be very much like a Java |
26 | interface. |
27 | |
28 | =head1 A SIMPLE ROLE |
29 | |
30 | Creating a role looks a lot like creating a Moose class: |
31 | |
32 | package Breakable; |
33 | |
34 | use Moose::Role; |
35 | |
36 | has 'is_broken' => ( |
37 | is => 'rw', |
38 | isa => 'Bool', |
39 | ); |
40 | |
41 | sub break { |
42 | my $self = shift; |
43 | |
44 | print "I broke\n"; |
45 | |
46 | $self->is_broken(1); |
47 | } |
48 | |
49 | Except for our use of C<Moose::Role>, this looks just like a class |
50 | definition with Moose. However, this is not a class, and it cannot be |
51 | instantiated. |
52 | |
53 | Instead, its attributes and methods will be composed into classes |
54 | which use the role: |
55 | |
56 | package Car; |
57 | |
58 | use Moose; |
59 | |
60 | with 'Breakable'; |
61 | |
62 | has 'engine' => ( |
63 | is => 'ro', |
64 | isa => 'Engine', |
65 | ); |
66 | |
67 | The C<with> function composes roles into a class. Once that is done, |
68 | the C<Car> class has an C<is_broken> attribute and a C<break> |
69 | method. The C<Car> class also C<does('Breakable')>: |
70 | |
c56e5db4 |
71 | my $car = Car->new( engine => Engine->new ); |
ef45e915 |
72 | |
c56e5db4 |
73 | print $car->is_broken ? 'Still working' : 'Busted'; |
74 | $car->break; |
75 | print $car->is_broken ? 'Still working' : 'Busted'; |
ef45e915 |
76 | |
77 | $car->does('Breakable'); # true |
78 | |
79 | This prints: |
80 | |
81 | Still working |
82 | I broke |
83 | Busted |
84 | |
85 | We could use this same role in a C<Bone> class: |
86 | |
87 | package Bone; |
88 | |
89 | use Moose; |
90 | |
91 | with 'Breakable'; |
92 | |
93 | has 'marrow' => ( |
94 | is => 'ro', |
95 | isa => 'Marrow', |
96 | ); |
97 | |
98 | =head1 REQUIRED METHODS |
99 | |
100 | As mentioned previously, a role can require that consuming classes |
101 | provide one or more methods. Using our C<Breakable> example, let's |
102 | make it require that consuming classes implement their own C<break> |
103 | methods: |
104 | |
105 | package Breakable; |
106 | |
107 | use Moose::Role; |
108 | |
109 | requires 'break'; |
110 | |
111 | has 'is_broken' => ( |
112 | is => 'rw', |
113 | isa => 'Bool', |
114 | ); |
115 | |
116 | after 'break' => sub { |
117 | my $self = shift; |
118 | |
119 | $self->is_broken(1); |
c56e5db4 |
120 | }; |
ef45e915 |
121 | |
122 | If we try to consume this role in a class that does not have a |
123 | C<break> method, we will get an exception. |
124 | |
125 | Note that attribute-generated accessors do not satisfy the requirement |
126 | that the named method exists. Similarly, a method modifier does not |
127 | satisfy this requirement either. This may change in the future. |
128 | |
129 | You can also see that we added a method modifier on |
130 | C<break>. Basically, we want consuming classes to implement their own |
131 | logic for breaking, but we make sure that the C<is_broken> attribute |
132 | is always set to true when C<break> is called. |
133 | |
134 | package Car |
135 | |
c56e5db4 |
136 | use Moose; |
ef45e915 |
137 | |
138 | with 'Breakable'; |
139 | |
140 | has 'engine' => ( |
141 | is => 'ro', |
142 | isa => 'Engine', |
143 | ); |
144 | |
145 | sub break { |
146 | my $self = shift; |
147 | |
c56e5db4 |
148 | if ( $self->is_moving ) { |
149 | $self->stop; |
ef45e915 |
150 | } |
151 | } |
152 | |
153 | =head1 USING METHOD MODIFIERS |
154 | |
155 | Method modifiers and roles are a very powerful combination. Often, a |
156 | role will combine method modifiers and required methods. We already |
157 | saw one example with our C<Breakable> example. |
158 | |
eb169874 |
159 | Method modifiers increase the complexity of roles, because they make |
c56e5db4 |
160 | the role application order relevant. If a class uses multiple roles, |
161 | each of which modify the same method, those modifiers will be applied |
162 | in the same order as the roles are used: |
eb169874 |
163 | |
164 | package MovieCar; |
165 | |
166 | use Moose; |
167 | |
168 | extends 'Car'; |
169 | |
170 | with 'Breakable', 'ExplodesOnBreakage'; |
171 | |
172 | Assuming that the new C<ExplodesOnBreakage> method I<also> has an |
173 | C<after> modifier on C<break>, the C<after> modifiers will run one |
174 | after the other. The modifier from C<Breakable> will run first, then |
175 | the one from C<ExplodesOnBreakage>. |
176 | |
177 | =head1 METHOD CONFLICTS |
178 | |
179 | If a class composes multiple roles, and those roles have methods of |
180 | the same name, we will have a conflict. In that case, the composing |
181 | class is required to provide its I<own> method of the same name. |
182 | |
183 | package Breakdances; |
184 | |
185 | use Moose::Role |
186 | |
187 | sub break { |
188 | |
189 | } |
190 | |
191 | If we compose both C<Breakable> and C<Breakdancer> in a class, we must |
192 | provide our own C<break> method: |
193 | |
194 | package FragileDancer; |
195 | |
196 | use Moose; |
197 | |
198 | with 'Breakable', 'Breakdancer'; |
ef45e915 |
199 | |
c56e5db4 |
200 | sub break { ... } |
201 | |
202 | =head1 METHOD EXCLUSION AND ALIASING |
203 | |
204 | If we want our C<FragileDancer> class to be able to call the methods |
205 | from both its roles, we can alias the methods: |
206 | |
207 | package FragileDancer; |
208 | |
209 | use Moose; |
210 | |
211 | with 'Breakable' => { alias => { break => 'break_bone' } }, |
212 | 'Breakdancer' => { alias => { break => 'break_dance' } }; |
213 | |
214 | However, aliasing a method simply makes a I<copy> of the method with |
215 | the new name. We also need to exclude the original name: |
216 | |
217 | with 'Breakable' => { |
218 | alias => { break => 'break_bone' }, |
219 | exclude => 'break', |
220 | }, |
221 | 'Breakdancer' => { |
222 | alias => { break => 'break_dance' }, |
223 | exclude => 'break', |
224 | }; |
225 | |
226 | The exclude parameter prevents the C<break> method from being composed |
227 | into the C<FragileDancer> class, so we don't have a conflict. This |
228 | means that C<FragileDancer> does not need to implement its own |
229 | C<break> method. |
230 | |
231 | This is useful, but it's worth noting that this breaks the contract |
232 | implicit in consuming a role. Our C<FragileDancer> class does both the |
233 | C<Breakable> and C<BreakDancer>, but does not provide a C<break> |
234 | method. If some API expects an object that does one of those roles, it |
235 | probably expects it to implement that method. |
236 | |
a4bd85ad |
237 | =head1 AUTHOR |
238 | |
239 | Dave Rolsky E<lt>autarch@urth.orgE<gt> |
240 | |
241 | =head1 COPYRIGHT AND LICENSE |
242 | |
243 | Copyright 2008 by Infinity Interactive, Inc. |
244 | |
245 | L<http://www.iinteractive.com> |
246 | |
247 | This library is free software; you can redistribute it and/or modify |
248 | it under the same terms as Perl itself. |
249 | |
250 | =cut |