new
строит строителя. Вы хотите, чтобы какой-то другой метод действительно возвращал построенный объект.
Вот пример:
class RepositoryBuilder {
has 'allow_network_repositories' => (
is => 'ro',
isa => 'Bool',
required => 1,
);
method build_repository(Uri $url) {
confess 'network access is not allowed'
if $url->is_network_url && !$self->allow_network_repositories;
my $class = $self->determine_class_for($url); # Repository::Whatever
return $class->new( url => $url );
}
}
role Repository { <whatever }
class Repository::File with Repository {}
class Repository::HTTP with Repository {}
Здесь строитель и построенный объект различны. Строитель
реальный объект, в комплекте с параметрами, которые можно настроить для создания
объекты, как того требует ситуация. Затем «построенные» объекты
просто вернуть значения метода. Это позволяет строить другие
строители в зависимости от ситуации. (Проблема с застройщиком
функции в том, что они очень негибкие - их трудно научить
новый особый случай. Эта проблема все еще существует с объектом-строителем,
но по крайней мере ваше приложение может создать подкласс, создать его экземпляр,
и передать этот объект всему, что нужно для создания объектов. Но
В этом случае лучше использовать внедрение зависимостей.)
Кроме того, нет необходимости, чтобы репозитории, которые вы строите, наследовали от
что угодно, им просто нужен тег, указывающий, что они являются репозиториями.
И это то, что делает наша Repository
роль. (Вы хотите добавить
Код API здесь и любые методы, которые следует использовать повторно. Но будь осторожен
о принудительном повторном использовании - вы уверены, что все помечены
Роль репозитория захочет этот код? Если нет, просто введите код в
другую роль и применить это к классам, которые требуют, чтобы
функциональность.) * +1010 *
Вот как мы используем созданный нами конструктор. Если, скажем, вы не хотите
коснитесь сети:
my $b = RepositoryBuilder->new( allow_network_repositories => 0 );
$b->build_repository( 'http://google.com/' ); # error
$b->build_repository( 'file:///home/whatever' ); # returns a Repository::Foo
Но если вы сделаете:
my $b = RepositoryBuilder->new( allow_network_repositories => 1 );
$b->build_repository( 'http://google.com/' ); # Repository::HTTP
Теперь, когда у вас есть строитель, который строит объекты так, как вам нравится,
вам просто нужно использовать эти объекты в другом коде. Итак, последний кусок
в загадке относится к «любому» типу объекта репозитория в другом
код. Это просто, вы используете does
вместо isa
:
class SomethingThatHasARepository {
has 'repository' => (
is => 'ro',
does => 'Repository',
required => 1,
);
}
И все готово.