С Moose::Manual::BestPractices страницы:Почему «очень плохая практика» отменяет новые при использовании Moose?
Переопределение
new
является очень плохая практика. Вместо этого вы должны использовать методыBUILD
илиBUILDARGS
, чтобы сделать то же самое. Когда вы переопределяетеnew
, Moose больше не может встроить конструктор, когда ваш класс является универсальным.
Мой вопрос: почему это считается очень плохой практикой?
Я думал, что встроенный конструктор просто означает, что конструктор был определен в том же пакете, что и класс. Если это правда, не означает ли это, что если вы перекроете new
в этом пакете, конструктор все равно будет считаться конструктором inline? Пожалуйста, поправьте меня, если я ошибаюсь. Я не совсем понимаю концепцию того, что означает, что конструктор является «встроенным».
Причина, по которой я столкнулся с этим вопросом, заключается в том, что я создаю скрипт, который строит список объектов. Если пользователь пытается создать новый объект, который идентичен одному в списке, я хочу остановить Moose
от создания нового объекта и просто вернуть ссылку на существующий.
Когда создается новый объект, я хочу нажать его в списке и вернуть новый объект. Когда делается попытка создать существующий объект, существующий объект должен быть возвращен и не помещен в список.
# Some pseudo code showing the logic of what I attempted
around BUILDARGS => sub {
my ($orig, $self, %args) = @_;
# loop through objects in list
for my $object (@list) {
# if $args used to define the new object
# match the arguments of any object in the list
# return the matched object
# I want this to directly return the object
# and skip the call to BUILD
}
return $self->orig(
# Insert args here
);
};
sub BUILD {
my ($self) = @_;
# I don't want this call to happen if the object already existed
push @list, $self;
}
При создании нового объекта я попытался использовать BUILD
толкать его на список, как только он будет создан. Проблема в том, что когда я попытался создать существующий объект и использовать BUILDARGS
для возврата существующего объекта, похоже, не останавливается Moose
от вызова BUILD
, который пытается вытолкнуть объект в список.
Единственный способ, которым мне удалось обойти это, было переопределить new
и вернуть его существующий объект без создания нового.
# Some pseudo code showing the overridden constructor
sub new {
my ($class, %args) = @_;
# loop through objects in list
for my $object (@list) {
# if $args used to define the new object
# match the arguments of any object in the list
# return the matched object
}
# Build the object
my $self = bless {
# Insert args here
}, $class;
# Add the object to the list
push @list, $object;
}
Переопределение new
работал, но если это на самом деле такая ужасная идея, так как документация Moose
, кажется, предполагает, есть лучший способ сделать это?
Я объявляю пакет неизменным, но мне нужно было добавить 'inline_constructor => 0'. Есть ли какой-либо способ достичь желаемой функциональности без полного переопределения «новых»? Или, если это невозможно, существует ли способ обеспечить, чтобы переопределенный «новый» все еще был «встроенным»? – tjwrona1992
@ tjwrona1992: Предлагаю вам взглянуть на ['MooseX :: Role :: Flyweight'] (https://metacpan.org/pod/MooseX::Role::Flyweight), который добавляет метод' instance', который ведет себя то же, что и 'new', но возвратит ранее созданный объект, если он был вызван ранее с теми же параметрами. – Borodin
Это похоже на потенциальное решение; однако он не является частью стандартного распределения ActivePerl. Где я работаю, сетевая безопасность очень строгая, и мы не можем ничего загрузить, поэтому я не могу получить какие-либо модули из cpan. Даже с помощью команды cpan для установки модулей происходит сбой. Есть ли способ сделать это без не-основного модуля? – tjwrona1992