On Fri, Feb 10, 2012 at 02:06:24PM -0500, Chris Prather wrote: > On Fri, Feb 10, 2012 at 12:27 PM, Ovid <curtis_ovid_...@yahoo.com> wrote: > > > > Of course, both Acme::Combat::Chipmunk and Acme::Combat::Normal implement > > the desired role. With that, you can swap out abilities as needed. > > What if Joe is bitten by a Chipmunk *and* a Zombie? You'll need to > carefully design your roles with composition in mind then. This is > what stopped my first go at this problem using an Array trait.
Right, this is the key point here. Roles are designed for composition into classes, and have an interface that makes sense for that kind of use case (where you can handle method conflicts and such when you're actually writing the class). Runtime application to instances does work, but only really works well for very simple cases where there aren't very many things interacting. Once you start trying to model more complicated things with roles, you will end up writing just as much (if not more) code trying to force roles into the model that your system needs as you would if you had just written that explicitly from the start (and it will end up being more difficult to understand and maintain too). One alternative to having to hardcode specific aspect behavior into each action is to make the aspects classes rather than roles, and have those classes consume roles corresponding to the actions. For instance, you could do something along these lines (note that this is effectively the same sort of model as Dist::Zilla uses for plugins): package Acme::Combat; use Moose; # ... sub attack { my $self = shift; for my $aspect ($self->aspects_with('Attack')) { $aspect->attack_effects(@_); } } package Acme::Combat::Normal; use Moose; with 'Acme::Combat::Aspect::Attack'; sub attack_effects { my $self = shift; my ($opponent) = @_; $opponent->decrease_hp(2); } This way, you can just swap out which aspects are attached to a given class, and things will just work. The advantage here is that you're explicitly determining what the composition behavior should be, so you don't have to try to trick roles into doing what you want. -doy