Неблагородные объекты Perl - ужасный дизайн?
Неужели небессмысленные объекты Perl означают ужасный дизайн?
Если да, может кто-нибудь объяснить это мне?
Кстати, вот обсуждение, которое вызвало этот вопрос, проверьте комментарии на вопрос
4 ответа
Нуждаясь unbless
конечно поднимает брови. Поскольку вы все еще можете использовать объект в качестве исходной структуры данных, это почти никогда не требуется.
Модули, которые разборчивы в получении необъявленных ссылок на хеш-объекты по сравнению с объектами, как правило, имеют опции, чтобы не быть такими разборчивыми, например, allow_blessed и convert_blessed в JSON.
Одно приложение - это объект, реализованный в виде хеш-ссылки, и вы также хотите перегрузить %{}
оператор разыменования [EDIT: и вы также хотите поддерживать Perls старше v5.10.1 - в противном случае вы должны просто использовать no overloading
.]
package Foo;
use overload '+' => sub { $_[0]->get + $_[1] },
...,
'%{}' => sub { return { foo => "bar", this => $_[0] } },
...;
Теперь для любого$foo
это имеет типFoo
, пытаясь получить доступ к элементу, как $foo->{$key}
вызовет ваш перегруженный %{}
метод, и ваш доступ не удастся.
Обходной путь - временно изменить тип вашего объекта при доступе к члену вашего объекта и вернуть его обратно, когда вы закончите. Вы можете сделать это, отбрасывая свой объект, но это чаще делается (и легче сделать), благословляя его до мусорной стоимости.
sub Foo::bar { # access 'bar' member of Foo object
my $self = shift;
# $self->{bar} will invoke Foo::{'%{}'}, and we don't wan't that
my $ref = ref $self;
unbless($self); # or bless $self, 'Not::An::Object::Name'
# now $self->{bar} is accessible
my $value = $self->{bar};
bless $self, $ref; # restore object type
return $value;
}
Другой пример приведен в разделе "Ссылки на два лица" вoverload
Я использую этот шаблон здесь, для другого примера.
Это пустой и глупый вопрос. У вас нет цели для unbless
но случайно выбрали его из неясного модуля CPAN, чтобы спросить, почему он отражает плохой дизайн. Вы можете также спросить, как объявить переменную, которая была объявлена с my
, Это также вполне возможно в коде XS, но я надеюсь, что это довольно глупо?
У меня проблема с unbless
является то, что вы создали структуру данных - от скалярной переменной или дескриптора файла до вложенного хеша или массива - и назвали bless
чтобы Perl знал, как разрешать вызовы методов для этого объекта
Так что теперь вы хотите unbless
Это. Это оставит данные нетронутыми, и основное отличие будет в том, что любые вызовы методов теперь будут приводить к фатальной ошибке.
Can't call method ... on unblessed reference
Так какой был твой unbless
за? Если вы полагаетесь на Perl, чтобы дать вам эту фатальную ошибку, то это так же легко назначить undef
к объекту, который вызывает эту фатальную ошибку вместо
Can't call method ... on an undefined value
но имеет то преимущество, что ваша структура данных может быть разрушена, чтобы освободить память
Если вы хотите что-то более твердое, то, потому что ссылки могут быть переданы на несколько разделов кода, unbless
был бы примером действия на расстоянии, которое дискредитируется гораздо большим количеством людей, чем я
Я думаюunbless
полезно, когда я хочу сохранить данные объекта, а не данные объекта с именем класса; именно тогда, когда природа данных вашего объекта предназначена для производственных данных, а не для ссылки на сам объект для работы.
package My::Pkg;
use Storable qw/dclone/;
use Data::Structure::Util qw/unbless/;
sub _distribute_private_attr {
$_[0]->{_private_attrs} = {...}
}
sub new {
my $obj = bless { Foo => [qw/bar/] };
$obj->_distribute_private_attr();
return $obj;
}
sub load {
my $cls = shift;
my $data = retrieve $_[0];
my $obj = bless $data, $cls;
$obj->_distribute_private_attr();
return $obj
}
sub save {
my $obj = shift;
my $data = unbless ( dclone $obj );
delete $data->{_private_attrs};
store $data, $_[0];
}
1;
package main;
use Some::Other::Mod;
my $obj = My::Pkg -> new;
$obj->{Bar} = "Baz";
$obj->save ("someFile");
my $obj2 = My::Pkg->load("someFile"); # Now we can do this
my $obj3 = Some::Other::Mod->load("someFile"); # or this
my $data = retrieve "someFile"; # or this
И теперь сохраненная структура данных может использоваться другими, не вмешиваясь в другие вещи класса, но при этом ничто не испортило экземпляр среды выполнения.