Во-первых, не вызывайте ваш метод 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, чтобы клонирование работало правильно.