Mooseでデザパタ - Compositeパターン
#!/usr/bin/env perl use strict; use warnings; { package Entry; use Moose::Role 'requires'; requires 'get_name'; requires 'get_size'; } { package File; use Moose; use Perl6::Say; with 'Entry'; has name => ( is => 'rw', isa => 'Str', required => 1 ); has size => ( is => 'rw', isa => 'Int', required => 1 ); sub get_name { my $self = shift; $self->name; } sub get_size { my $self = shift; $self->size; } sub print_list { my ( $self, $prefix ) = @_; say $prefix . '/' . $self->name . '(' . $self->size . ')'; } } { package Directory; use Moose; use Moose::Autobox; use Perl6::Say; with 'Entry'; has name => ( is => 'rw', isa => 'Str', required => 1 ); has directory => ( is => 'rw', isa => 'ArrayRef', default => sub { [] } ); sub get_name { my $self = shift; $self->name; } sub get_size { my $self = shift; my $size = 0; foreach my $entry ( @{ $self->directory } ) { $size += $entry->get_size; } return $size; } sub add { my ( $self, $entry ) = @_; $self->directory->push($entry); } sub print_list { my ( $self, $prefix ) = @_; say $prefix . '/' . $self->get_name . '(' . $self->get_size . ')'; foreach my $entry ( @{ $self->directory } ) { $entry->print_list( $prefix . "/" . $self->get_name ); } } } use Perl6::Say; say "Making root entries..."; my $root_dir = Directory->new( name => "root" ); my $bin_dir = Directory->new( name => "bin" ); my $tmp_dir = Directory->new( name => "tmp" ); my $usr_dir = Directory->new( name => "usr" ); $root_dir->add($bin_dir); $root_dir->add($tmp_dir); $root_dir->add($usr_dir); $bin_dir->add( File->new( name => "vi", size => 10000 ) ); $bin_dir->add( File->new( name => "latex", size => 20000 ) ); $root_dir->print_list(" ");
Moose的なポイントは、
- Mooseのインターフェースとしての機能としてRoleを使って、Entryの実装を強制する点
でしょうか
See also:
http://www.ceres.dti.ne.jp/~kaga/composite.txt
# Moose::Autoboxを少し拡張すれば、ほとんどRubyのコードと等価なコードにできそうですね
# 暇なときにパッチ作るかなぁ