04c5613ccae9492f29e4a8b022b253253890b121
[gitmo/Moose.git] / lib / Moose / Cookbook / Recipe2.pod
1
2 =pod
3
4 =head1 NAME
5
6 Moose::Cookbook::Recipe2 - A simple Bank Account example
7
8 =head1 SYNOPSIS
9
10   package BankAccount;
11   use strict;
12   use warnings;
13   use Moose;
14   
15   has 'balance' => (isa => 'Int', is => 'rw', default => 0);
16   
17   sub deposit {
18       my ($self, $amount) = @_;
19       $self->balance($self->balance + $amount);
20   }
21   
22   sub withdraw {
23       my ($self, $amount) = @_;
24       my $current_balance = $self->balance();
25       ($current_balance >= $amount)
26           || confess "Account overdrawn";
27       $self->balance($current_balance - $amount);
28   }
29   
30   package CheckingAccount;
31   use strict;
32   use warnings; 
33   use Moose;
34   
35   extends 'BankAccount';
36   
37   has 'overdraft_account' => (isa => 'BankAccount', is => 'rw');        
38   
39   before 'withdraw' => sub {
40       my ($self, $amount) = @_;
41       my $overdraft_amount = $amount - $self->balance();
42       if (self->overdraft_account && $overdraft_amount > 0) {
43           $self->overdraft_account->withdraw($overdraft_amount);
44           $self->deposit($overdraft_amount);
45       }
46   };
47
48 =head1 DESCRIPTION
49
50 In the first recipe we showed how to build basic Moose classes 
51 whose attributes had various accessor schemes and built in 
52 type constraints. However our objects were very data-oriented, 
53 and did not have many behavioral aspects to them (i.e. - methods). 
54 In this recipe, we will expand upon the concepts from the first 
55 recipe and give a more realistic scenario of more behavior 
56 oriented classes.  
57
58 We are using an example of a bank account, which has a standard 
59 account (you can deposit money, withdraw money and check your 
60 current balance), and a checking account which has optional 
61 overdraft protection. The overdraft protection will protect the 
62 owner of the checking account by automatically withdrawing the 
63 needed funds from the overdraft account to ensure that a check 
64 will not bounce. 
65
66 Now, onto the code. The first class B<BankAccount> introduces a 
67 new attribute feature, that of a default value. 
68
69   has 'balance' => (isa => 'Int', is => 'rw', default => 0);
70
71 This tells is that a B<BankAccount> has a C<balance> attribute, 
72 which is has the C<Int> type constraint, a read/write accessor, 
73 and a default value of C<0>. This means that every instance of 
74 B<BankAccount> that is created will have it's C<balance> slot 
75 initialized to C<0>. Very simple really :)
76
77 Next come the methods. The C<deposit> and C<withdraw> methods 
78 should be fairly self explanitory, they are nothing specific to 
79 Moose, just your standard Perl 5 OO.
80
81 Now, onto the B<CheckingAccount> class. As you know from the 
82 first recipe, the keyword C<extends> sets a class's superclass 
83 relationship. Here we see that B<CheckingAccount> is a 
84 B<BankAccount>. The next line introduces yet another new aspect 
85 of Moose, that of class based type-constraints.
86
87   has 'overdraft_account' => (isa => 'BankAccount', is => 'rw');
88
89 Up until now, we have only had C<Int> type constraints, which 
90 (as I said in the first recipe) is a built-in type constraint 
91 that Moose provides for you. The C<BankAccount> type constraint 
92 is new, and was actually defined at the moment we created the 
93 B<BankAccount> class itself. In fact, for every Moose class that 
94 you define, a corresponding type constraint will be created for 
95 that class. This means that in the first recipe, a C<Point> and 
96 C<Point3D> type constraint were created, and in this recipe, both 
97 a C<BankAccount> and a C<CheckingAccount> type constraint were 
98 created. Moose does this as a convience for you so that your 
99 class model and the type constraint model can both be kept in 
100 sync with one another. In short, Moose makes sure that it will 
101 just DWIM (1).
102
103 Next, we come to the behavioral part of B<CheckingAccount>, and 
104 again we see a method modifier, but this time we have a C<before> 
105 modifier.
106
107   before 'withdraw' => sub {
108       my ($self, $amount) = @_;
109       my $overdraft_amount = $amount - $self->balance();
110       if (self->overdraft_account && $overdraft_amount > 0) {
111           $self->overdraft_account->withdraw($overdraft_amount);
112           $self->deposit($overdraft_amount);
113       }
114   };
115
116 Just as with the C<after> modifier from the first recipe, Moose 
117 will handle calling the superclass method (in this case the 
118 C<BankAccount::withdraw> method). The C<before> modifier shown 
119 above will run (obviously) I<before> the code from the superclass 
120 with run. The C<before> modifier here implements the overdraft 
121 protection by first checking if there are enough available 
122 funds in the checking account and if not (and if there is an overdraft 
123 account available), it transfers the appropriate funds into the 
124 checking account.
125
126 As with the method modifier in the first recipe, there is another 
127 way to accomplish this same thing using the built in C<SUPER::> 
128 pseudo-package. So the above method is equivalent to the one here.
129
130   sub withdraw {
131       my ($self, $amount) = @_;
132       my $overdraft_amount = $amount - $self->balance();
133       if ($overdraft_amount > 0 && $self->overdraft_account) {
134           $self->overdraft_account->withdraw($overdraft_amount);
135           $self->deposit($overdraft_amount);
136       }
137       $self->SUPER::withdraw($amount);
138   }
139
140 The benefits of taking the method modifier approach is that the 
141 author of the B<BankAccount> subclass does not need to remember 
142 to call C<SUPER::withdraw> and to pass it the C<$amount> argument. 
143 Instead the method modifier assures that all arguments make it 
144 to the superclass method correctly. But this is actually more 
145 than just a convience for forgetful programmers, it also helps 
146 isolate subclasses from changes in the superclasses. For instance, 
147 if B<BankAccount::withdraw> were to add an additional argument 
148 of some kind, the version of B<CheckingAccount::withdraw> which 
149 uses C<SUPER::withdraw> would not pass that extra argument 
150 correctly. Whereas the method modifier version of would pass 
151 all arguments along correctly automatically.
152
153 Just as with the first recipe, object instantiation is a fairly 
154 normal process, here is an example:
155   
156   my $savings_account  = BankAccount->new(balance => 250);
157   my $checking_account = CheckingAccount->new(
158                                                  balance => 100,
159                                                  overdraft_account => $savings_account
160                                              );
161
162 And as with the first recipe, a more in-depth example of using 
163 these classes can be found in the F<t/002_basic.t> test file.
164
165 =head1 CONCLUSION
166
167 The aim of this recipe was to take the knowledge learned in the 
168 first recipe and expand upon it within a more realistic use case. 
169 I hope that this recipe has accomplished this goal. The next 
170 recipe will expand even more upon the capabilties of attributes
171 in Moose to create a behaviorally sophisticated class almost 
172 entirely defined by attributes.
173
174 =head1 FOOTNOTES
175
176 =over 4
177
178 =item (1)
179
180 Moose does not attempt to encode a class's is-a relationships 
181 within the type constraint hierarchy. Instead Moose just considers 
182 the class type constraint to be a subtype of C<Object>, and 
183 specializes the constraint check to allow for subclasses. This 
184 means that an instance of B<CheckingAccount> will pass a 
185 C<BankAccount> type constraint successfully. For more details, 
186 please refer to the L<Moose::Util::TypeConstraints> documentation.
187
188 =back
189
190 =head1 SEE ALSO
191
192 =over 4
193
194 =item Acknowledgement
195
196 The BankAccount example in this recipe is directly taken from the 
197 examples in this chapter of "Practical Common Lisp". A link to that 
198 can be found here:
199
200 L<http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html>
201
202 =back
203
204 =head1 AUTHOR
205
206 Stevan Little E<lt>stevan@iinteractive.comE<gt>
207
208 =head1 COPYRIGHT AND LICENSE
209
210 Copyright 2006 by Infinity Interactive, Inc.
211
212 L<http://www.iinteractive.com>
213
214 This library is free software; you can redistribute it and/or modify
215 it under the same terms as Perl itself.
216
217 =cut