package BCast; sub spawn { my ($package, $alias) = @_; my $self = $package->new($alias); POE::Session->create( object_states => [$self => [qw(_start xmit join split)],],); } sub new { my ($package, $alias) = @_; return bless {alias => $alias}, $package; } sub _start { my ($kernel, $self) = @_[KERNEL, OBJECT]; $kernel->alias_set($self->{alias}); $self->{reg} = []; } sub xmit { my ($kernel, $self, $something) = @_[KERNEL, OBJECT, ARG0]; foreach my $s (@{$self->{reg}}) { $kernel->post(@$s, $something); } } sub join { my ($kernel, $self, $something) = @_[KERNEL, OBJECT, ARG0]; push @{$self->{reg}}, $something; } sub split { my ($kernel, $self, $something) = @_[KERNEL, OBJECT, ARG0]; $self->{reg} = [grep { $_->[0] ne $something->[0] or $_->[1] ne $something->[1] } @{$self->{reg}}]; }
With this form, it becomes dead simple to reuse code. Simply overload the the package:
package BCast::Once; @ISA = qw(BCast); sub join { my ($sender, $self, $something) = @_[SENDER, OBJECT, ARG0]; $self->{joined}{$sender->ID}{$something} = 1; delete $self->{reg}; } sub split { my ($sender, $self, $something) = @_[SENDER, OBJECT, ARG0]; my $sender = $sender->ID; if ($something) { delete $self->{already}{$sender}{$something}; delete $self->{already}{$sender} unless keys %{$self->{already}{$sender}}; } else { delete $self->{already}{$sender}; } delete $self->{reg}; } sub xmit { my $self = shift @_; $self->{reg} ||= [map { keys %$_ } keys %{$self->{already}}]; $self->SUPER::xmit(@_); }
This looks stunningly similar /Package Methods, only HEAP and $heap have been replaced with OBJECT and $self.
Advantages
- Fully OO.
- C<$_[OBJECT]> can have non-POE related methods, because we don't depend on C<$_[HEAP]>.
Disadvantages
- Some people don't like OO.
- Because @_ has so much in it, one has to do silly things like C<shift(@_)->SUPER::subroutine(@_);> to call parent POE-related methods.
Notes
I found that it can be easy to form circular references - if you store the session object in the object whose methods you are using for states.
For example, I tend to create and store session objects in my own objects:
sub new { my ($package, $alias) = @_; my $self = bless {alias => $alias}, $package; $self->{session} = POE::Session->create( object_states => [$self => [qw(_start _stop xmit join split)],],); $self; } # ... as above ... # now, don't forget to do this ! # it breaks the reference-cycle sub _stop { delete $_[OBJECT]->{session}; }
I know its not necessarily great form to keep the session object reference, but I do.
--Lachie
Of course, you could use [weak references] instead.
--Merlyn
See also: /Anonymous Inline Subrefs, /Inline Subrefs, /Package Methods moved here