Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 如何创建其派生类由创建属性隐式指定的对象?_Perl_Inheritance_Constructor_Design Patterns_Creation - Fatal编程技术网

Perl 如何创建其派生类由创建属性隐式指定的对象?

Perl 如何创建其派生类由创建属性隐式指定的对象?,perl,inheritance,constructor,design-patterns,creation,Perl,Inheritance,Constructor,Design Patterns,Creation,我正在寻找以下的模式。(我正在使用Perl,但我认为这种语言并不特别重要) 父类为Foo,子类为Bar、Baz、Bazza 构造Foo的方法之一是解析字符串,该字符串的一部分将隐式指定要创建的类。例如,如果它启动了“http:”,那么它就是一个条,但是如果它不启动,但是它包含“[Date]”,那么Baz会喜欢它,等等 现在,如果Foo知道它的所有子元素,什么字符串是Bar,什么是Baz等等,那么它可以调用相应的构造函数。但是,一个底层阶级不应该对其子女有任何了解 我想要的是Foo的构造函数能够依

我正在寻找以下的模式。(我正在使用Perl,但我认为这种语言并不特别重要)

父类为Foo,子类为Bar、Baz、Bazza

构造Foo的方法之一是解析字符串,该字符串的一部分将隐式指定要创建的类。例如,如果它启动了“http:”,那么它就是一个条,但是如果它不启动,但是它包含“[Date]”,那么Baz会喜欢它,等等

现在,如果Foo知道它的所有子元素,什么字符串是Bar,什么是Baz等等,那么它可以调用相应的构造函数。但是,一个底层阶级不应该对其子女有任何了解

我想要的是Foo的构造函数能够依次尝试它的子类,直到其中一个说“是的,这是我的,我来创建这个东西”

我意识到,在一般情况下,这个问题没有很好的定义,因为可能会有多个子类接受该字符串,因此它们被调用的顺序很重要:忽略这一点,并假设该字符串的特征只有一个子类会喜欢该字符串

我想到的最好的方法是,子类在初始化时向基类“注册”,这样它就可以得到一个构造函数列表,然后循环遍历它们。但是有没有一个更好的方法,我错过了

示例代码:

package Foo;

my @children;

sub _registerChild
{
  push @children, shift();
}

sub newFromString
{
  my $string = shift;
  foreach (@children) {
    my $object = $_->newFromString(@_) and return $object;
  }
  return undef;
}

package Bar;
our @ISA = ('Foo');

Foo::_registerChild(__PACKAGE__);

sub newFromString
{
  my $string = shift;
  if ($string =~ /^http:/i) {
    return bless(...);
  }
  return undef;
}

您可以在类Foo中实现任意查找算法,该算法搜索现有的子类。可能基于与子类一起提供的配置文件,或者基于您可能想到的任何其他机制

然后,类Foo将在运行时检测现有的客户机类,并依次调用它们


此外,您还可以缓存查找结果,并接近您自己描述的注册表解决方案。

您是否可以使用?这将消除注册的需要

我以前采用的方法是使用Module::Pluggable加载我的子模块(这允许我通过简单地编写和安装子模块来添加新的子模块)。每个子类都有一个构造函数,该构造函数要么返回一个受祝福的对象,要么返回一个未定义的对象。你循环你的插件,直到你得到一个对象,然后返回它

比如:

package MyClass;
use Module::Pluggable;

sub new
{
    my ($class, @args) = @_;
    for my $plugin ($class->plugins)
    {
       my $object = $plugin->new(@args);
       return $object if $object;
    }
}

也有,但这可能有点超出了您的需要。

如果您对不包含儿童信息的父类以及您将建立子类适合性的任务委托给该类本身的方法发表评论,那么从父类中排除类选择可能是正确的类并为此任务创建一个单例

至少这是我的偏好。。。由此,您当前的父类(可能在您的子类中具有一些公共功能)可能会成为抽象类或接口

然后,singleton可以管理所有子类的构造及其分布(如果它们不起作用,则克隆它们?)。。。此外,可以将子类移动到单独的dll中以促进分离

抱歉,这不是一个直接的解决方案。
我在过去通过管理singleton中的类列表来实现这一点,就像您在这里一样。singleton背后的想法是,如果您确实想使用任何昂贵的反射,您只需执行一次

似乎您正试图将一个类同时作为基类和工厂。不要。使用两个单独的类。大概是这样的:

package Foo;

package Bar;
use base 'Foo';

package Baz;
use base 'Foo';

package Bazza;
use base 'Foo';

package Factory;
use Bar;
use Baz;
use Bazza;

sub get_foo {
    my ($class, $string) = @_;
    return Bar->try($string) || Baz->try($string) || Bazza->try($string);
}
然后像这样使用它:

my $foo = Factory->get_foo($string);

这样,基类就不需要知道子类,只有工厂需要知道。子类也不需要相互了解,只有Factory需要知道要尝试的子类的详细信息以及顺序。

谢谢。在我看来,如果我必须做这样的事情,那么我的“注册”就更简单、更清晰了。我希望有一个我错过的既定模式。决定取决于您想要解决的用例。如果您想让您的Foo工厂对未知的第三方子类保持开放,那么您将进行查找。如果您生活在一个受控制的环境中,只支持您自己的代码,那么注册表就可以了。谢谢。从逻辑上讲,Module::Pluggable正是我想要的;但它可能不适合我们的情况,因为它可能不会出现在我们用户的机器上,所以我们必须用我们自己的模块分发它。与我的注册解决方案相比,它也是“神奇的”,所以它可能不那么清晰。但是谢谢你让我注意到这一点。这有点神奇,但是默认的行为将只加载MyClass::Plugin名称空间中的类(该名称空间很容易重写)。因此,注册实际上等同于在该名称空间中创建模块。很明显,它是一个CPAN模块,但如果您现在能够在没有CPAN(或大量车轮改造)的情况下用Perl管理任何类型的严肃应用程序,我会感到惊讶。一旦创建了对象,它们将通过多态性获得正确的方法,这就是如何处理我所担心的还没有子类对象的情况。通过这种方法,您甚至可以在代码中占有一席之地,需要了解完整的子类集。我认为这比注册表解决方案更糟糕。如果您想添加/删除一个子类,那么您必须将其他地方的一些代码进行一致的修改。因此,您的想法并没有增加针对更改的灵活性,因为模式通常旨在。@mkoeller,让工厂在特定名称空间ala Module::Pluggable中自动加载一组类是很简单的。一般来说,我更喜欢对这类事情直言不讳,以避免意外,但这更像是一个品味问题,而不是灵活性问题