Composite パターン

Composite パターン。

Composite パターンは複数の処理クラスが持つオブジェクトを「複合」し、
複合したオブジェクトを持つクラスが、処理クラスの処理すべてを、一括で行ってくれるものです。

{
    package Car::Factory::Interface;
    use Moose::Role;
    requires qw( made_car examine_car );
    no Moose::Role;
    1;
}

{
    package Car::Factory::PassengerCar;
    use Moose;
    with 'Car::Factory::Interface';

    has 'displacement' => (
        metaclass => 'Number',
        is => 'rw',
        isa => 'Num',
        required => 1,
        provides => {
            mul => 'displacement_mul'
        }
    );

    __PACKAGE__->meta->make_immutable;

    no Moose;
    sub made_car {
        my ( $self, $factor ) = @_;
        $self->displacement_mul( $factor );
    }

    sub examine_car {
        my $self = shift;
        print $self->displacement, "ccの乗用車が完成。\n";
    }

    1;
}

{
    package  Car::Factory::Truck;
    use Moose;
    with 'Car::Factory::Interface';

    has 'weight' => (
        metaclass => 'Number',
        is => 'rw',
        isa => 'Num',
        required => 1,
        provides => {
            mul => 'weight_mul'
        }
    );

    __PACKAGE__->meta->make_immutable;

    no Moose;
    sub made_car {
        my ( $self, $factor ) = @_;
        $self->weight_mul( $factor );
    }

    sub examine_car {
        my $self = shift;
        print $self->weight, "tのトラックが完成。\n";
    }
    1;
}

{
    package Car::Factory;
    use Moose;

    use MooseX::AttributeHelpers;
    with 'Car::Factory::Interface';

    has 'car_means' => (
        metaclass => 'Collection::Array',
        is => 'rw',
        isa => 'ArrayRef',
        auto_deref => 1,
        default => sub { [] },
        provides => {
            push => 'car_add',
        }
    );

    __PACKAGE__->meta->make_immutable;
    no Moose;
    sub made_car {
        my ( $self, $factor ) = @_;
        my $list = $self->car_means;
        foreach my $car_means ( @$list ){
             $car_means->made_car( $factor );
        }
    }

    sub examine_car {
        my $self = shift;
        my $list = $self->car_means;
        foreach my $car_means ( @$list ){
             $car_means->examine_car();
        }
    }
    1;
}

{
    package main;
    my $car1 = Car::Factory::PassengerCar->new( displacement => 550 );
    my $car2 = Car::Factory::PassengerCar->new( displacement => 1000 );
    my $car3 = Car::Factory::PassengerCar->new( displacement => 3000 );

    my $car4 = Car::Factory::Truck->new( weight => 3 );
    my $car5 = Car::Factory::Truck->new( weight => 2 );
    my $car6 = Car::Factory::Truck->new( weight => 5 );

    my $factory = Car::Factory->new;
    $factory->car_add( $car1 );
    $factory->car_add( $car2 );
    $factory->car_add( $car3 );
    $factory->car_add( $car4 );
    $factory->car_add( $car5 );
    $factory->car_add( $car6 );

    $factory->made_car(1);
    $factory->examine_car();
    1;
}

またまた拙い例ですが、上記のコードはある自動車工場をイメージしました。

工場では、乗用車を製造するCar::Factory::PassengerCarクラスと、
トラックを製造するCar::Factory::Truckクラスがあり、
担当のクラスがそれぞれ自動車を製造しています。

ある日工場では、効率性を上げるためにCar::Factoryクラスが追加されました。
Car::Factoryクラスは、乗用車クラスとトラッククラスを一括で処理してくれるクラスであるため、
生産性は向上します。

勘違いとかありましたら、ご指摘いただければありがたく思います。
よろしくお願いいたします。