Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl中的数据封装?_Perl_Encapsulation - Fatal编程技术网

Perl中的数据封装?

Perl中的数据封装?,perl,encapsulation,Perl,Encapsulation,你好,Perl社区,等等。几年前我就开始使用Perl了,但由于我一直在使用Perl,我意识到我对Perl的了解还不够 在过去的4年里,我写了一个相当大的脚本,并试图用OO风格来完成。我知道Perl这是一个已经在多个地方讨论过的问题,有几种可能的解决方法,但没有一种方法一定是理想的 使用Tie::SecureHash讨论闭包、标量和有限访问散列等选项,首选最后一种方法 认为在perl中,有时应该违反封装,尽管注释对此提出了一些负面意见 您还可以查看Perl 5对象的详细信息。编写它是为了鼓励使用。

你好,Perl社区,等等。几年前我就开始使用Perl了,但由于我一直在使用Perl,我意识到我对Perl的了解还不够


在过去的4年里,我写了一个相当大的脚本,并试图用OO风格来完成。我知道Perl这是一个已经在多个地方讨论过的问题,有几种可能的解决方法,但没有一种方法一定是理想的

使用Tie::SecureHash讨论闭包、标量和有限访问散列等选项,首选最后一种方法

认为在perl中,有时应该违反封装,尽管注释对此提出了一些负面意见

您还可以查看Perl 5对象的详细信息。编写它是为了鼓励使用。Perl支持部分封装:委派和信息隐藏。封装的另一部分就是我所谓的“行为有界数据”,将数据与行为关联起来。在维基百科关于“”的文章中,它建议“封装是指两个相关但不同的概念之一”(斜体)。第二个是

  • 一种便于将数据与操作该数据的方法(或其他函数)捆绑在一起的语言结构
文章的一个很好的部分是“信息隐藏”。Perl允许使用隐藏复杂性的OO类型,只要您不太在意它。我在Perl中一直使用封装。有太多的问题需要我一次又一次地解决和使用,我的想法是只要接口类不“进入”,行为就应该如预期的那样

大多数动态语言都以安全封装的方式完成了很多工作。尽管如此,Perl允许您将行为分配给您想要的任何类型的引用,并且在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;
    }

}