【问题标题】:Can Perl handle this OOP concept - Explained in Animal TermsPerl 可以处理这个 OOP 概念吗?用动物术语解释
【发布时间】:2013-06-18 21:51:39
【问题描述】:

对不起,我很模糊,但我不知道这个概念的名称。我会尽力解释。我会试着用动物的方式来表达,这样会更容易。

我有一个通用的超类。这个超类包含所有动物都必须做的功能。例如,我不想在每个动物子类中重新定义“take_breath”子类,所以我在 Animals 超类中定义一次,所有动物(Animals::Cat、Animals::Dog 和 Animals::Llama)都可以简单地访问 $self->take_breath()。这些动物也经历了许多相同的初始化例程,而不是每次我简单地调用 $class->SUPER::new(@_) 以及做特定于该动物的事情时都重新定义它们。

每次初始化动物时都会这样说,它会通过它的超类的初始化例程。有数百只动物,它们运行了数百次。问题不大。

这些动物很聪明,并且知道如何使用 LWP::UserAgent 网络浏览器。为了访问互联网,他们必须登录网页并设置会话 cookie。他们都共享相同的登录名并希望共享相同的浏览器。在我当前的实现中,登录例程是超类新方法的一部分。这意味着当动物被初始化时,它会运行并且动物登录。正如我所说,我有数百只动物并且不想触发数百个 POST 请求。我想以某种方式启动登录例程并使其成为超类的一部分。然后每只动物都可以通过 $self->{'ua'} 访问“共享”网络浏览器。

我希望这能解释它,我不确定这个 OOP 术语叫什么。

TLDR 适合那些不喜欢动物的人

我在超类中有一个登录例程,它创建 LWP::UserAgent、登录并设置会话 cookie。子类都可以共享一个登录名。我不想为每个子类触发数百个 POST 请求来登录。我想以某种方式登录一次并与所有子类共享准备好的 $ua 对象。

【问题讨论】:

  • 没有注意到本文中的问题符号;)但是是的,您可以轻松实现这一点。

标签: perl class oop subclass superclass


【解决方案1】:

有两种方法可以解决这个问题:

1。包变量

并非每个动物实例都有 UA,但 UA 是作为 Animal 的一部分。您可以在启动时初始化 UA。动物可以通过访问器或变量访问 UA:

package Animal;

my $ua = LWP::UserAgent->new();

sub ua { $ua }

然后

my $ua = $self->ua();

package Animal;

our $ua = LWP::UserAgent->new();

然后

my $ua = $Animal::ua;

对此的技术术语是类变量,或者在Java 静态方法静态变量等语言中。

Java 翻译:

class Animal {
  private static LWP.UserAgent ua = new LWP.UserAgent();
  public static LWP.UserAgent getUa() { return ua }
  ...
}

class Animal {
  public static LWP.UserAgent ua = new LWP.UserAgent();
  ...
}

2。 state变量

在较新的 Perls (>= v5.10?) 中,您可以使用 state 声明变量。他们声明词法变量。该变量在程序的生命周期内被初始化一次,而不是每次执行语句时(就像 my 一样)。

use feature 'state';
package Animal;
sub new {
  my ($class, %args) = @_;
  state $ua = LWP::UserAgent->new;
  bless { ua => $ua, %args } => $class;
}

然后

my $ua = $self->{ua};

使用do 块执行更广泛的初始化可能很有用

state $ua = do {
  my $ua = LWP::UserAgent->new;
  ...;
  $ua;
};

或将初始化卸载到子中:state $ua = make_ua();

如果您必须针对较早的 perls,您可以将 new 子包含在单独的范围内,并在那里将变量声明为词法以获得类似的效果:

package Animal;

{
  my $ua = LWP::UserAgent->new;
  sub new {
    my ($class, %args) = @_;
    bless { ua => $ua, %args } => $class;
  }
}

这里唯一的区别是何时 UA 被初始化。 (当然还有烦人的大括号的数量。)初始化可以推迟,正如Len Jaffe 提到的:

package Animal;

{
  my $ua; # just declare scope here
  sub new {
    my ($class, %args) = @_;
    $ua ||= LWP::UserAgent->new;  # $ua is false until initialized
    bless { ua => $ua, %args } => $class;
  }
}

因为对象是引用,所以所有动物都会得到相同的 UA。

特别是在 C/C++ 中,这也称为 静态变量state 修饰符可以看作是一个非 OO 单例构造函数。

【讨论】:

  • 还有单例模式实现,其中构造函数调用 LWP::UA->new() 但“缓存”类变量中的引用:$ua ||= LWP::UA->new ()
  • @LenJaffe 是的,我们可以使用完整的 OO 并实现实际的单例模式。但是,使用 stateperlish 的方式(我会说)。
  • 为什么类变量被第一个构造函数实例化后会是undef?
  • 我阅读了您评论的原始版本,my 仍然存在
  • 习惯的力量。对不起。很快注意到并更正了:-)你的回答很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多