perl6 上的单例实现

Singleton implementation on perl6

我在Rosetta代码上看了下面的代码http://rosettacode.org/wiki/Singleton#Perl_6 它在 Perl6 中实现了 Singleton

class Singleton {

    has Int $.x is rw;
    # We create a lexical variable in the class block that holds our single instance.
    my Singleton $instance = Singleton.bless; # You can add initialization arguments here.
    method new {!!!} # Singleton.new dies.
    method instance { $instance; }
}

my $a=Singleton.bless(x => 1);
my $b=Singleton.bless(x=> 2);


say $a.x;
say $b.x;

#result 
# 1
# 2

但似乎使用此实现我可以创建相同 class 的两个实例,请参见上面的示例,

是否有一个选项可以防止仅对同一 class 的一个实例实施?

Perl 以提供多种做事方式而自豪,让您可以选择适合您的口味和手头应用程序的方式。我这样说是为了强调这是一种简单但可靠、希望不言自明的方式 - 我不会将其作为 "the best" 提出,因为这取决于您的情况。

#!/usr/bin/env perl6

class Scoreboard {
  has Str $.home-team ;
  has Str $.away-team ;
  has Int $.home-score = 0 ;
  has Int $.away-score = 0 ;
  my Scoreboard $instance;

  method new(*%named) {
      return $instance //= self.bless(|%named) ;
  }

  multi method goal($team where * eq $!home-team,  Int :$points = 6) {
      $!home-score += $points
  }

  multi method goal($team where * eq $!away-team,  Int :$points = 6) {
      $!away-score += $points
  }

  method Str {
      "At this vital stage of the game " ~

      do given $!home-score <=> $!away-score {
          when More {
              "$!home-team are leading $!away-team, $!home-score points to $!away-score"
          }
          when Less {
              "$!home-team are behind $!away-team, $!home-score points to $!away-score"
          }
          default {
              "the scores are level!  $!home-score apeice!"
          }
      }
  }
}

my $home-team = "The Rabid Rabbits";
my $away-team = "The Turquoise Turtles";  # Go them turtles!

my $scoreboard = Scoreboard.new( :$home-team , :$away-team );

$scoreboard.goal($home-team, :4points) ;
say "$scoreboard";
$scoreboard.goal($away-team) ;
say "$scoreboard";
my $evil_second_scoreboard = Scoreboard.new;
$evil_second_scoreboard.goal($home-team, :2points) ;
say "$evil_second_scoreboard";

这会产生;

At this vital stage of the game The Rabid Rabbits are leading The Turquoise Turtles, 4 points to 0
At this vital stage of the game The Rabid Rabbits are behind The Turquoise Turtles, 4 points to 6
At this vital stage of the game the scores are level!  6 apeice!

这会覆盖默认的 new(通常由 class Mu 提供)并保留对我们自己的引用(即这个对象)在私有 class 数据中。对于私有 class 数据,我们使用用 my 声明的词法范围标量。 //.defined 的运算符形式。因此,在第一个 运行 上,我们调用 bless 分配对象并初始化属性,然后将其赋值给 $instance。在对 new 的后续调用中,$instance 被定义并立即返回。

如果要防止有人直接调用bless,可以加上;

method bless(|) {
    nextsame unless $instance;
    fail "bless called on singleton Scoreboard"
}

这将确保只有第一次调用有效。