Visitor

再帰の部分で苦しむ。シーケンス図を描くことで(本にも載っている)掴みやすくはなる。ShallowCopyとは何なのかDeepCopyとは何なのかとかが少し理解できていないと苦しい。なぜShallowCopyなのかもしくはDeepCopyなのかが分っていれば楽なのだろうけれどそれを理解できるのはまだ先な気がする。

use strict;
use warnings;

{
    package Visitor;
    use strict;
    use warnings;
    sub visit {die;}
}
{
    package ListVisitor;
    use strict;
    use warnings;
    our @ISA = qw/Visitor/;
    sub new {
        my ($class, $currentDir) = @_;
        my $self = {
            currentDir => $currentDir || '',
        };
        return bless $self, $class;
    }
    sub visit {
        my ($self, $obj) = @_;
        if(ref($obj) eq 'Directory'){
            print $self->{currentDir}."/".$obj->{name},"\n";
            $self->{currentDir} .= "/".$obj->{name};
            $_->accept(ListVisitor->new($self->{currentDir})) for @{$obj->{entry}};
        }
        elsif(ref($obj) eq 'File'){
            print $self->{currentDir}."/".$obj->getName,"\n";
        }
        else {
            die 'ERROR';
        }
    }
}
{
    package Element;
    use strict;
    use warnings;
    sub accept {die;}
}
{
    package Entry;
    use strict;
    use warnings;
    our @ISA = qw/Element/;
    sub add {die;}
}
{
    package File;
    use strict;
    use warnings;
    our @ISA = qw/Entry/;
    sub new {
        my ($class, $name, $size) = @_;
        my $self = {
            name => $name,
            size => $size,
        };
        return bless $self, $class;
    }
    sub getName { return $_[0]->{name}; }
    sub getSize { return $_[0]->{size}; }
    sub accept {
        my ($self, $v) = @_;
        $v->visit($self);
    }
}
{
    package Directory;
    use strict;
    use warnings;
    our @ISA = qw/Entry/;
    sub new {
        my ($class, $name) = @_;
        my $self = {
            name => $name,
            entry => [],
        };
        return bless $self, $class;
    }
    sub add {
        my ($self, $item) = @_;
        push @{$self->{entry}}, $item;
    }
    sub accept {
        my ($self, $v) = @_;
        $v->visit($self);
    }
}

use Data::Dumper;

my $root = Directory->new('root');
my $usr = Directory->new('usr');
my $tmp = Directory->new('tmp');
my $vi = File->new('vi', 100);

$usr->add($vi);
$root->add($usr);
$root->add($tmp);

print Dumper($root);
$root->accept(ListVisitor->new());