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 代码以及应重用的任何方法。但要小心强制重用 - 您确定所有标记为 Repository 角色的东西都需要该代码吗?如果不是,只需将代码放在另一个角色并将其应用于需要该功能的类。)
以下是我们如何使用我们创建的构建器。例如,如果您不想接触网络:
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
现在您有了一个可以按照您喜欢的方式构建对象的构建器,您只需在其他代码中使用这些对象。所以拼图的最后一块是指其他代码中的“任何”类型的 Repository 对象。这很简单,您使用does
而不是isa
:
class SomethingThatHasARepository {
has 'repository' => (
is => 'ro',
does => 'Repository',
required => 1,
);
}
你完成了。