2010年5月25日星期二

[PerlChina] Moose 介绍 [zz]

发信人: Dieken (风催草低 - 明月何尝不照人), 信区: Perl
标 题: Moose 介绍
发信站: 水木社区 (Wed May 19 10:31:17 2010), 转信

貌似没人对 Moose 感兴趣?

这几天简单用了下,之前觉得 Moose 比较博大精深,所以一般手写
或者用 Class::Struct,这次提起兴致学习了下,发现简单使用即有
很高回报,并没有当初想象的复杂,呵呵。

Moose 是 Perl 5 的一种新的 OO 实现,跟内置的基于 package 的
简单 OO 实现相比:

* 复杂一些(这是必然的)
* 基于 Class::MOP,提供元类的支持,也就是说,有很方便的反射(内省)API 用了
* 语法简单,相比手写 new/getter/setter 来说。

Mouse 是 Moose 的简化版,没有提供扩展,只有 Moose 的 OO 核心功能,效率
据说比 Moose 快了三四倍。如果你只用到 Moose 的 OO 核心功能,那么可以用
Any::Moose 在两种实现间自动切换,另外 Any::Moose 还提供自动加载 MooseX::*
扩展的功能,但由于没有现成的 MouseX::* 对应物,所以要么直接用 Moose,要么
自己写一个 MouseX 扩展了。

对于简单的使用,只要关注 Moose 的 class 和 role 即可,前者就是大家熟知的
类,后者则相当于接口,role 的方法是 mixin 到使用它的类里的,这个类不是
继承自 role。关于 mixin 可以 google "Perl mixin"。

一个 Moose 类的框架:
=====================================================
package MyClass;
use Any::Moose; # 默认用 Mouse,用环境变量 ANY_MOOSE=Moose 来用 Moose
use namespace::autoclean; # 在模块结束时自动清除导入过的符号
# 避免类继承时出意外
our $VERSION = '0.01';

extends 'MyBaseClass'; # extends 函数,继承某个类,默认是继承 Moose::Object。
with 'Role1', 'Role2'; # with 函数,将指定 role 的成员插入当前类中

has 'name' => (is => 'rw', isa => 'Str', required => 1);
# has 函数,指定类的成员变量,Moose 里称为 attribute

sub hello { # 定义一个成员函数,Moose 里称为 method
my ($self) = @_;
print "Hello ", $self->name, "\n";
}

no Any::Moose; # 去掉 Any::Moose 导入进来的符号,在有 namespace::autoclean
# 的情况下是多余的
__PACKAGE__->meta->make_immutable(); # 不允许此类的成员动态变化,因此会
# 稍微缺乏灵活性,但提高性能
1; # 返回 1 以让包加载成功
=================================================================

如果不想要 Any::Moose 提供的灵活性,把上面的 Any::Moose 替换成 Moose
或者 Mouse 即可。

在 has 函数,is 有两种取值,ro 和 rw。 ro 表示只能在构造函数中设置,不能用
$obj->someAttr(xxx) 这样的 setter 设置。

required => 1 指必须在构造时参数中指定。

isa => 'Str' 指这个成员的类型,类型定义在 Moose::Manual::Types 中有说明,
有了类型,就可以做一些有趣的事情,比如用反射 API 根据类属性生成 SQL 建表
语句以及 HTML form。

Moose 自动给类定义了 new 和 DESTROY,如果你想在构造和析构时做点事情,可以
用 BUILD 和 DEMOLISH 函数,参考 perldoc Moose::Manual::Construction。注意
Mouse <= 0.50 在遇到 DEMOLISH 时会 segment fault 崩溃。

自动定义的 new 接收一个 hash,跟成员变量同名的键对应的值会被赋值给此成员变量。
自动生成的 setter 和 getter 都是一个函数,名字与成员变量名字相同,比如
$obj->name("jack"); print $obj->name;

Role 的定义也是非常简单的:
====================================
package MyRole;
use Any::Moose 'Role';

requires 'somefunc'; # requires 函数,要求使用此 role 的类具备 some_func 成员

has ....; # 会被插入使用此 role 的类中
sub ....; # 会被插入使用此 role 的类中

no Any::Moose;
1;
=======================================
MooseX::Storage 是 Moose 的一个序列化、持续存储框架,利用 role 特性
给某个类插入 pack/unpack/freeze/thraw/load/store 方法,值得一看。

如果要使用 Moose 的反射 API,可以参考 Class::MOP 文档以及 Moose::Meta::XXX
或者 Mouse::Meta::XXX,需要注意的是每个 Moose 对象都有 meta 成员函数,
获取其元信息,比如下面模仿 MooseX::Storage 的 pack 函数:

sub pack {
my ($obj) = @_;

my $h = {};
$h->{__CLASS__} = $obj->meta->name . "-" . UNIVERSAL::VERSION($obj);
my @attributes = $obj->meta->get_all_attributes;

for my $attr (@attributes) {
if ($attr->has_value($obj)) {
$h->{$attr->name} = $attr->get_value($obj);
}
}

return $h;
}

Moose 是很强大方便的 OO 实现,更多特性可以挖掘 Moose 的 perldoc。

--
您收到此邮件是因为您订阅了 Google 网上论坛的"PerlChina Mongers 讨论组"论坛。
要向此网上论坛发帖,请发送电子邮件至 perlchina@googlegroups.com
要取消订阅此网上论坛,请发送电子邮件至 perlchina+unsubscribe@googlegroups.com
若有更多问题,请通过 http://groups.google.com/group/perlchina?hl=zh-CN 访问此网上论坛。

没有评论: