Просто отметьте некоторые ответы:
Вызов bless
в BUILD или где-либо за пределами MOP всегда недопустим. (Если вы должны rebless, есть Class::MOP::Class->rebless_instance
!)
Я рекомендую не разрешать new
возвращать что-либо, кроме экземпляра __PACKAGE__
. Если вам нужен метод, который создает экземпляр чего-либо, назовите его как-нибудь еще. Пример:
class Message {
method new_from_string(Str $msg){
my ($foo, $bar, $baz) = ($msg =~ /<...>/); # blah blah blah
my $class = "Message::${foo}::$baz";
Class::MOP::load_class($class);
return $class->new( bar => $msg );
}
}
Затем, когда вы хотите создать буквальное сообщение:
Message->new( whatever => 'you want' );
Если вы хотите проанализировать строку и вернуть правильный подкласс сообщения:
Message->new_from_string( 'OH::Hello!' );
Наконец, если нет смысла создавать экземпляр Message, тогда он не должен быть классом. Это должна быть роль.
Конечно, вы можете справиться со строительством другого объекта. Просто убедитесь, что этот другой объект отвечает, например, только за понимание формата строки, а не за внутренности сообщения:
class MessageString {
has 'string' => ( initarg => 'string', reader => 'message_as_string' );
method new_from_string(ClassName $class: Str $string) {
return $class->new( string => $string );
}
method as_message_object {
# <parse>
return Message::Type->new( params => 'go here', ... );
}
}
role Message { ... }
class Message::Type with Message { ... }
Теперь вас больше не интересует наличие какого-то «суперкласса», отвечающего за создание «подклассов», что, я думаю, является лучшим дизайном. (Помните, что MessageString не имеет особой власти над классами, которые выполняют функцию «Сообщение». Это ключевой момент; он отвечает только за понимание сообщений со строкой.)
В любом случае, теперь вы просто:
my $data = <>; # Yup, I called it $data. Sorry, Andy Lester.
my $parsed = MessageString->new_from_string( $data );
my $message = $parsed->as_message_object;
$message->interact_with
(Вы знаете "MVC"? Это похоже.)