How can I create an object whose derived class is specified implicitly by the creation properties?

I am looking for a template for the following. (I work in Perl, but I do not think this language is particularly important).

With parent class Foo and kids bar, Baz, Bazza.

One method of constructing Foo is to parse a string, and part of this string will implicitly determine which class should be created. For example, if it launches "http:", then it is a bar, but if it does not contain, but contains "[Date]", then the Base likes it, etc.

Now, if Foo knows about all its children, and which line is a bar, what is Baz, etc., it can call the corresponding constructor. But the base class should not have any knowledge about its children.

I want the Foo constructor to try their children one at a time, until one of them says, "Yes, this is mine, I will create a thing."

I understand that in the general case this problem is not defined correctly, since there can be more than one child who will accept the string, and therefore the order in which they are called matters: ignore this and assume that the characteristics of the string are such that there is only one the child class will love the string.

The best I came up with is that the child classes β€œregister” with the base class during initialization, to get a list of constructors, and then skip them. But is there a better method that I am missing?

Code example:

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;
}
+3
source share
4

, Module:: Pluggable? .

, , , Module:: Pluggable ( , ). , , undef. , , .

- :

package MyClass;
use Module::Pluggable;

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

: Factory, .

+5

, , factory. . 2 . - :

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. , factory , .

+1

Foo, . , , , , .

Foo .

, .

0

, , , , .

, ... ( ), , , , .

then a singleton could control the construction of all the child classes and their distribution (clone them if they are not functional?) ... in addition, the child classes can be moved to a separate dll to facilitate separation.

Sorry this is not a direct solution. I have done this in the past, managing a list of classes in a singlet like you are here. singleton's idea is that if you want to use any expensive reflection, you only need to do this once.

0
source

Source: https://habr.com/ru/post/1710561/


All Articles