생성 속성에 의해 암시적으로 파생 클래스가 지정되는 객체를 생성하려면 어떻게 해야 합니까?

StackOverflow https://stackoverflow.com/questions/1000681

문제

나는 다음에 대한 패턴을 찾고 있습니다.(저는 Perl로 작업하고 있지만 언어는 특별히 중요하지 않다고 생각합니다.)

부모 클래스 Foo와 자식 Bar, Baz, Bazza가 있습니다.

Foo를 생성하는 방법 중 하나는 문자열을 구문 분석하는 것이며, 해당 문자열의 일부는 생성될 클래스를 암시적으로 지정합니다.예를 들어 'http:'로 시작하면 Bar이고, 그렇지 않지만 '[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;
}
도움이 되었습니까?

해결책

아마도 당신은 이것을 구현할 수 있습니다 모듈 :: 플러그 가능? 이것은 등록이 필요하지 않습니다.

내가 이전에 취한 접근법은 모듈을 사용하는 것이 었습니다 :: pluggeable은 자녀 모듈을로드하는 것이 었습니다 (이를 통해 간단히 작성하고 설치하여 새 자식 모듈을 추가 할 수있었습니다). 각 자식 수업에는 축복받은 대상이나 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;
    }
}

거기 있습니다 수업 : 공장 또한 그것은 당신의 요구에 대해 약간 위에있을 수 있습니다.

다른 팁

단일 클래스가 기본 클래스와 공장이 되려고하는 것 같습니다. 하지 않다. 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);

이런 식으로 귀하의 기본 수업은 자녀 수업에 대해 알 필요가 없으며 공장에서만 알 수 없습니다. 그리고 아동 수업은 서로에 대해 알 필요가 없으며, 공장에서만 시도 할 어린이 수업과 주문에 대한 세부 사항을 알아야합니다.

기존 아동 클래스를 검색하는 클래스 FOO에서 임의의 조회 알고리즘을 구현할 수 있습니다. 자식 수업이 제공되는 구성 파일 또는 생각할 수있는 다른 메커니즘을 기반으로 할 수 있습니다.

그런 다음 FOO 클래스는 런타임에 기존 클라이언트 클래스를 감지하여 차례로 전화합니다.

추가로 조회 결과를 캐시하고 이미 설명한 레지스트리 솔루션에 가까워 질 수 있습니다.

Chillidren에 대한 정보가 포함되지 않은 상위 ​​클래스에 대한 의견과 하위 클래스 적합성을 설정하는 작업을 클래스 자체에 위임하는 방법을 고려한다면 상위 클래스에서 클래스 선택을 제외하고 이 작업을 위한 싱글톤입니다.

적어도 그게 내 취향이겠지...여기에서 현재 상위 클래스(아마도 하위 클래스 전체에 걸쳐 몇 가지 공통 기능을 갖고 있음)가 추상화 또는 인터페이스가 될 수 있습니다.

그런 다음 싱글톤은 모든 하위 클래스의 구성 및 배포를 관리할 수 있습니다(기능적이지 않으면 복제합니까?).또한 하위 클래스를 별도의 DLL로 이동하여 분리를 촉진할 수 있습니다.

죄송합니다. 직접적인 해결책은 아닙니다.나는 과거에 여기 있는 것처럼 싱글톤의 클래스 목록을 관리하여 이 작업을 수행했습니다.싱글톤의 기본 아이디어는 비용이 많이 드는 리플렉션을 사용하려면 한 번만 수행하면 된다는 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top