Perl中的数据封装?
你好,Perl社区,等等。几年前我就开始使用Perl了,但由于我一直在使用Perl,我意识到我对Perl的了解还不够Perl中的数据封装?,perl,encapsulation,Perl,Encapsulation,你好,Perl社区,等等。几年前我就开始使用Perl了,但由于我一直在使用Perl,我意识到我对Perl的了解还不够 在过去的4年里,我写了一个相当大的脚本,并试图用OO风格来完成。我知道Perl这是一个已经在多个地方讨论过的问题,有几种可能的解决方法,但没有一种方法一定是理想的 使用Tie::SecureHash讨论闭包、标量和有限访问散列等选项,首选最后一种方法 认为在perl中,有时应该违反封装,尽管注释对此提出了一些负面意见 您还可以查看Perl 5对象的详细信息。编写它是为了鼓励使用。
在过去的4年里,我写了一个相当大的脚本,并试图用OO风格来完成。我知道Perl这是一个已经在多个地方讨论过的问题,有几种可能的解决方法,但没有一种方法一定是理想的 使用Tie::SecureHash讨论闭包、标量和有限访问散列等选项,首选最后一种方法 认为在perl中,有时应该违反封装,尽管注释对此提出了一些负面意见 您还可以查看Perl 5对象的详细信息。编写它是为了鼓励使用。Perl支持部分封装:委派和信息隐藏。封装的另一部分就是我所谓的“行为有界数据”,将数据与行为关联起来。在维基百科关于“”的文章中,它建议“封装是指两个相关但不同的概念之一”(斜体)。第二个是
- 一种便于将数据与操作该数据的方法(或其他函数)捆绑在一起的语言结构
标记->{ID}
访问,但它在幕后为您做了几件事
这大致相当于:
package TAG;
use strict;
use warnings;
sub getID{
my($self) = @_;
return $self->{ID};
}
sub setID{
my($self,$new_id) = @_;
# die if $new_id is anything other than a string
# ( the one produced by Moose is smarter )
die if ref $new_id;
die unless defined $new_id;
$self->{ID} = $new_id
}
sub hasID{
my($self) = @_;
return exists $self->{ID}
}
sub clearID{
my($self) = @_;
delete $self->{ID}
}
sub name{
my($self) = @_;
return $self->{name}
}
# The constructor provided by Moose is vastly superior
# to the one shown here.
sub new{
my($class,%opt) = @_;
my $self = bless {}, $class;
die unless exists $opt{ID}; # this was the required => 1, from above
$self->setID($opt{ID});
die unless exists $opt{name}; # this was the required => 1, from above
$self->{name} = $opt{name};
}
有一种理论认为,给定代码中的bug数量与代码行数成正比
如果这是真的,那么我会说这个版本的bug要少得多
事实上,如果我实现了为您所做的一切,那么代码行数将是现在的两倍多
如果您确实需要阻止
$TAG->{ID}
访问,那么您可以在仍然使用的情况下使用另一个元类。不要问我怎么做,我最近才开始使用 perl中最简单的解决方案就是在变量前面加上前缀(即“_ID”或“private_ID”或您想要的任何内容),然后不记录它,因为它不是接口的一部分
还有其他的方法,这是可以做到的,但是你必须问谁会尝试这样破坏它,如果他们想误用你的代码,那么不管怎样你都会遇到麻烦。如果你想要封装,为什么要在构造函数中破坏它?要直接咀嚼
$self->{ID}
,应该使用setID
方法进行设置
你可以做各种各样的奇怪的事情来防止访问和咀嚼你的对象内部
最简单的方法之一是使用lock\u散列来锁定对象。这样,任何修改其内部的尝试都将抛出致命错误
也可以使用由内而外的对象
您可以重载哈希访问,以防止在子类之外进行访问:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my $f = Foo->new();
$f->bar(15);
print Dumper $f;
eval {
$f->{bar} = 23;
1;
} or do {
print "Direct access error: $@";
};
print Dumper $f;
BEGIN {
package Foo;
use strict;
use warnings;
use overload '%{}' => '_HASH_DEREF';
sub new {
return bless {};
}
sub bar {
my $self = shift;
$self->{bar} = shift if @_;
return $self->{bar};
}
sub _HASH_DEREF {
my $caller = caller;
die "Illegal access to object internals"
unless $caller eq __PACKAGE__;
return shift;
}
}
您可以使用方法名来调用子例程,以生成用作S3存储桶的神奇秘密值
你可以用任何你能想到的奇怪的东西来隐藏数据
Perl对象允许您在后端执行任何疯狂的操作来处理存储和/或封装
如果你有一个团队欺骗并直接访问对象的内部,那么你就有一个社会问题需要解决。技术修复可能会有所帮助。真正的解决办法是改变开发团队的行为。谢谢你的链接,我现在有一些东西要读。似乎在回答我的问题。Perl5肯定是OO,而且比现在人们使用的大多数其他语言都要多。至于带有爆炸性诱杀装置的狂暴围栏,你应该期望人们表现得像成年人,而不是恶作剧的孩子。除了功能接口,不要记录任何东西。无问题的结束。现在我知道在对象散列键前面加上{u:typing->{u ID}前缀的真正原因变得太尴尬了。“Perl并不迷恋强制隐私。它宁愿你呆在它的起居室之外,因为你没有被邀请,而不是因为它有一把猎枪。”-Larry Wall,这一切都很好,但是,不提问题和回答问题是两码事。如果我们在回答问题时保持建设性,针对最初的问题,避免对他人无礼,可能会更好。谢谢你的输入,我承认,我在准备问题时违反了自己的规则,在那之前,它一直在代码中。有这样一个约定是个好主意。我不需要阻止,只是如果不可能的话,它就不会发生。我想我会仔细看看moose,可能会有一个像
$TAG->{u ID}
这样的约定来避免意外使用代码>
$CurrentItem->{ID} = "Something";
package TAG;
use Moose;
has ID => (
reader => 'getID', # this is the only one that is needed
writer => 'setID',
predicate => 'hasID',
clearer => 'clearID',
isa => 'Str', # this makes setID smarter
required => 1, # forces it to be included in new
);
has name => (
is => 'ro', # same as reader => 'name',
required => 1, # forces it to be included in new
);
# Notice that you don't have to make your own constructor.
# In fact, if you did, you would effectively break Moose
# so don't do that.
package TAG;
use strict;
use warnings;
sub getID{
my($self) = @_;
return $self->{ID};
}
sub setID{
my($self,$new_id) = @_;
# die if $new_id is anything other than a string
# ( the one produced by Moose is smarter )
die if ref $new_id;
die unless defined $new_id;
$self->{ID} = $new_id
}
sub hasID{
my($self) = @_;
return exists $self->{ID}
}
sub clearID{
my($self) = @_;
delete $self->{ID}
}
sub name{
my($self) = @_;
return $self->{name}
}
# The constructor provided by Moose is vastly superior
# to the one shown here.
sub new{
my($class,%opt) = @_;
my $self = bless {}, $class;
die unless exists $opt{ID}; # this was the required => 1, from above
$self->setID($opt{ID});
die unless exists $opt{name}; # this was the required => 1, from above
$self->{name} = $opt{name};
}
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my $f = Foo->new();
$f->bar(15);
print Dumper $f;
eval {
$f->{bar} = 23;
1;
} or do {
print "Direct access error: $@";
};
print Dumper $f;
BEGIN {
package Foo;
use strict;
use warnings;
use overload '%{}' => '_HASH_DEREF';
sub new {
return bless {};
}
sub bar {
my $self = shift;
$self->{bar} = shift if @_;
return $self->{bar};
}
sub _HASH_DEREF {
my $caller = caller;
die "Illegal access to object internals"
unless $caller eq __PACKAGE__;
return shift;
}
}