Как скопировать все свойства класса в новый подкласс в Perl? - PullRequest
2 голосов
/ 22 июня 2010
my $t=TT::Pop->new(name => "shadowfax", color => "white");
my $w=TT::Pop::Subs->new($t);

Как написать TT :: Pop :: Subs :: new (), чтобы я мог сделать так, чтобы $ w содержал все свойства из $ t? Другими словами, я хочу инициализировать класс его суперклассом.

В этом случае все свойства из $ t должны быть доступны только для чтения, поэтому копирование по ref допустимо. (Я не уверен, что Perl может сделать эти свойства доступными только для чтения)

Ответы [ 3 ]

2 голосов
/ 22 июня 2010

Используйте Clone, чтобы сделать глубокую копию вашей структуры данных и благословить новый хеш:

use Clone qw(clone);

my $w = bless clone($t), 'TT::Pop::Subs';

Или, если вы хотите создать конструктор копирования в TT :: Pop :: Subs:

# In TT::Pop
use base 'Clone'; 

# In TT::Pop::Subs
sub new {
  my ($class, $source) = @_;
  return bless $source->clone, $class;
}

Подробнее о клонировании читайте здесь: http://search.cpan.org/~rdf/Clone-0.31/Clone.pm Конечно, есть много других модулей, которые делают то же самое (глубокие копии структур данных), просто выберите тот, который вам больше нравится.

2 голосов
/ 23 июня 2010

Во-первых, не вызывайте ваш метод new называйте его promote или что-то в этом роде.

У меня смешанные чувства по поводу того, как обращаться с этим дизайном. Моя первая реакция заключается в том, что вы должны использовать методы доступа и «вручную» копировать значения в новый объект.

sub promote {
    my $class = shift;
    my $obj   = shift;

    my %args = map { $_ => $obj->$_ } qw(
        attribute
        another
        this_one
        that_one
    );

    return $class->new( %args );
}

Это изолирует ваш подкласс от изменений в родительском элементе.

Ваш родительский класс может теперь быть или стать наизнанку объектом или чем-то еще, что не clone хорошо. Критический атрибут в родительском объекте может быть заменен методом, который генерирует его из других атрибутов.

Очевидно, что степень связи между родительским и дочерним классом неизбежна. Но этот подход помогает минимизировать его.

Другой способ, который кажется очевидным, - это использовать clone и rebless, как предлагает jkramer. Большая проблема в том, что у вас есть следующие ограничения:

  • объекты вашего родительского класса должны быть клонируемыми
  • ваш родительский и дочерний классы должны реализовывать хранилище одинаково.
  • методы accessor / mutator не должны использовать префикс имени класса для доступа к атрибуту. Это означает, что класс Foo сохраняет attrib в $self->{'Foo::attrib'} = 'value';, а Foo :: Bar сохраняет их в $self->{'Foo::Bar::attrib'} = 'value';

Для клонирования я бы использовал Storable dclone. Преимущество его состоит в том, что он является базовым модулем, и многие другие экзотические реализации объектов предоставляют хуки для Storable, чтобы клонирование работало правильно.

1 голос
/ 22 июня 2010
sub new {
    my $this = shift;
    my $class = ref($this) || $this;
    my $SuperClass = shift;
    my $self = ref($SuperClass)?{%$SuperClass,}:{};
    bless $self, $class;
    return $self;
}

Ну, это делает копию хэша.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...