The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Book::Chinese::MasterPerlToday::Moose - Moose, OO

DESCRIPTION

Perl 的面对对象系统很强大(Moose 是由 Perl 编写),但并不是很好使用。建议使用 Moose

学习 Moose 最好的方法是阅读 Moose::Manual

对象系统

如果没有 Moose,Perl5 的 OO 应该是比较繁琐的。

  package Person;

  use strict;
  use warnings;

  sub new {
      my $class = shift;
      my %p = ref $_[0] ? %{ $_[0] } : @_;
      
      return bless \%p, $class;
  }

基本上你在写一些无用的东西,没有任何一行代码是跟实际应用的代码有关的。bless 是什么?这样的代码让人很迷惑。

Moose 的意义在于它可以让你专注于写什么(what),而不是怎么写(how)。

  package Person;
  
  use Moose;

概念

  • Attribute 属性

    CPAN 上拥有上百个创建 Accessor 的模块。其中包括最流行的 Class::AccessorClass::Accessor::FastMoose 不是最快的(Class::XSAccessor 目前来说最快),但却是最强大的。

  • Role

    Role 与 use base 或者 extends 不同。with 'Role' 类似于将 Role 里的整个代码复制到 with 的模块里。

  • Method modifiers

  • Type

  • Constructor & Destructor

细节例子

  • handles

    delegation 委托,委派。你可以将你自己所需要写的一些 subs 委托给其他的模块来处理,这样外部看起来就像这些 subs 就是属于这个包的。

        package A;
        
        use Moose;
        has 'ua' => (
            is  => 'rw',
            isa => 'LWP::UserAgent',
            lazy => 1,
            default => sub {
                LWP::UserAgent->new
            },
            handles => ['get', 'post', 'head', 'request']
        );

    使用 handles 后,A->new 之后可以直接调用 get, post 等方法。 A->new->get 等同于 A->new->ua->get

    handles 接受 ARRAY | HASH | REGEXP | ROLE | DUCKTYPE | CODE, 上面的例子是 ARRAY。

    HASH 可以让你使用不同的 sub 名字。比如

        handles => {
            get_url => 'get'
        }

    这种用法在当你的模块里已经有一个 get 的时候就非常有用。sub get 是你原来的 get, 而 A->new->get_url = A->new->ua->get

    其他的诸如 REGEXP, ROLE, CODE, DUCKTYPE 都有点高级,在有需要的时候可以去 moose@perl.org 或者 irc.perl.org #moose 咨询。

  • init_arg

      package AAAA;
      use Moose;
      has 'bigness' => (
          is       => 'ro',
          init_arg => 'size',
      );

    初始化的时候就要用 AAAA->new( size => 1 );

    如果你不允许一个变量在 new 里被初始化,可以参考如下:

      has '_genetic_code' => (
          is         => 'ro',
          lazy_build => 1,
          init_arg   => undef,
      );
  • MooseX::Types

    一般建议使用 MooseX::Types 而不是内置的 Moose Type。

    Moose Type 是全局类型,当你使用多个外部包的时候就有可能会造成类型冲突(除非所有的外部包都是用各自的 'packageA.name.' 作为前缀)。MooseX::Types 是属于当前包变量的类型,不容易冲突。

    Moose Type 是放在引号之内如 'Int',这种检测是在运行时检测。而 MooseX::Types 是不放在引号里的(如 Int),这种在编译时就会检测。

    MooseX::Types 拥有更多的变量。更容易扩展。常见的如 MooseX::Types::Path::Class

  • Roles 和 Traits

    Traits 其实就是 Role。它们的区别在于:

    • Traits 可以拥有一个短名字

    • 通常在编译时使用的是 Role,在运行时使用的是 Trait

      这意味这 Role 是影响了整个 Class,而 Trait 仅仅影响了 Class 的某个实例(instance)

    如果你的模块允许用户配置来使用哪些 traits 的话,一般参考 MooseX::Traits

MooseX

Moose 所开发的软件

但你在写一个小脚本的时候,你可能不会觉得 Moose 怎么有用。但当你写一个很大的系统的时候,你会由衷地为自己选择 Moose 而感到幸运。

  • Catalyst, Reaction

    Catalyst 应当是使用 Moose 最广的例子。而 Reaction 应该是最复杂的例子。

  • Dist::Zilla

    Dist::Zilla 拥有一个与 MooseX::Object::Pluggable 不同的写 Plugins 的技巧。

      $_->before_build for $self->plugins_with(-BeforeBuild)->flatten;
      
      $_->gather_files    for $self->plugins_with(-FileGatherer)->flatten;
      $_->prune_files     for $self->plugins_with(-FilePruner)->flatten;
      $_->munge_files     for $self->plugins_with(-FileMunger)->flatten;
      $_->setup_installer for $self->plugins_with(-InstallTool)->flatten;
      
      $_->after_build({ build_root => $build_root })
        for $self->plugins_with(-AfterBuild)->flatten;

    代码使用不同的 Role 来依次执行 Plugins,简洁而有效。

  • KiokuDB

  • TryCatch

  • More

    http://cpants.perl.org/dist/used_by/Moose

    不要因为担心 Moose 的启动速度而放弃它,这点速度是绝对物有所值的。

资源

SEE ALSO

Moose, Moose::Manual

AUTHOR

Fayland Lam, <fayland at gmail.com>

COPYRIGHT & LICENSE

Copyright (c) 2009 Fayland Lam

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.