本に忠実な感じで、visitorクラスを。
package Visitor;
use Moose::Role;
requires 'visit';
package ListVisitor;
use Moose;
use Perl6::Say;
with 'Visitor';
sub visit {
my ($self, $entry) = @_;
my $currentdir = "";
if(ref($entry) eq "File"){
say $currentdir . "/" . $entry->toString();
}
elsif (ref($entry) eq "Directory"){
say $currentdir . "/" . $entry->toString();
my $savedir = $currentdir;
$currentdir = $currentdir . "/" . $entry->getName();
my $it = $entry->iterator();
while($it->has_next){
my $e = $it->next;
$e->accept($self);
}
$currentdir = $savedir;
}
}
package Element;
use Moose::Role;
requires 'accept';
package Entry;
use Moose::Role;
use Perl6::Say;
with 'Element';
requires 'getName';
requires 'getSize';
sub add {say "method add";}
sub iterator {say "method iterator";}
sub toString {
my $self = shift;
return $self->getName() . " (" . $self->getSize() . ")";
}
package File;
use Moose;
with 'Entry';
has name => (isa => 'Str', is => 'rw');
has size => (isa => 'Int', is => 'rw');
sub getName {
my $self = shift;
return $self->name;
}
sub getSize {
my $self = shift;
return $self->size;
}
sub accept {
my ($self,$v) = @_;
$v->visit($self);
}
package Directory;
use Moose;
use MooseX::Iterator;
with 'Entry';
has name => (isa => 'Str', is => 'rw');
has directory => (isa => 'ArrayRef', is => 'rw', default => sub{[]});
sub getName {
my $self = shift;
return $self->name;
}
sub getSize {
my $self = shift;
my $size = 0;
my $it = $self->iterator();
while ( $it->has_next ) {
my $e = $it->next;
$size += $e->getSize();
}
return $size;
}
sub add {
my ($self, $entry) = @_;
push @{$self->directory}, $entry;
return $self;
}
sub iterator {
my $self = shift;
return MooseX::Iterator::Array->new( collection => $self->directory );
}
sub accept {
my ($self,$v) = @_;
$v->visit($self);
}
package main;
use Perl6::Say;
say "Making root entries";
my $rootdir = Directory->new( name => "root" );
my $bindir = Directory->new( name => "bin" );
my $tmpdir = Directory->new( name => "tmp" );
my $usrdir = Directory->new( name => "usr" );
$rootdir->add($bindir);
$rootdir->add($tmpdir);
$rootdir->add($usrdir);
my $vi = File->new( name => "vi", size => 10000 );
my $latex = File->new( name => "latex", size => 20000 );
$bindir->add($vi);
$bindir->add($latex);
my $visit = ListVisitor->new();
$rootdir->accept($visit);
実行
Making root entries
/root (30000)
/bin (30000)
/vi (10000)
/latex (20000)
/tmp (0)
/usr (0)
javaのコードだとvisitメソッドをオーバーロードしてんだけどMooseでもできるのかどうかはわからなかった。
withとextendsの使い分けが微妙にわかってなさげ。このパターンだとsuperが必要ないからか?
directryクラスでのみ必要なメソッドは抽象クラスでエラーにしたい場合どうすべきかちょっとわからない。