Skip to content

Commit

Permalink
finished blessed_references.pod
Browse files Browse the repository at this point in the history
  • Loading branch information
horus committed Nov 24, 2010
1 parent a6c04fe commit 02d89a9
Showing 1 changed file with 87 additions and 127 deletions.
214 changes: 87 additions & 127 deletions sections/blessed_references.pod
@@ -1,38 +1,37 @@
=head1 Blessed References
=encoding utf8

=head1 经 bless 后的引用

Z<blessed_references>

Perl 5's default object system is deliberately minimal. Three simple rules
combine to form the simple--though effective--basic object system:
Perl 5 的默认对象系统故意最小化。以下三条简单的规则相组合构成了简单────但有效的
────基本对象系统:

=over 4

=item * A class is a package.
=item * 一个类就一个包;

=item * A method is a function.
=item * 一个方法就是一个函数;

=item * A (blessed) reference is an object.
=item * 一个(bless 后的)引用就是一个对象。

=back

X<bless>
X<operators; bless>

You've already seen the first two rules with Moose. The third rule is new.
The C<bless> keyword associates the name of a class with a reference, such that
any method invocation performed on that reference uses the associated class for
resolution. That sounds more complicated than it is.
你已经在 Moose 里见过了前两条规则。第三条规则是新出现的。C<bless> 关键字将一个类
的名称和一个引用关联起来,使得任何在该引用上进行的方法调用由与之相关联的类来解析。
它听上去比实际的要复杂一些。

=begin sidebar

Though these rules explain Perl 5's underlying object system, they are somewhat
more minimal in practice than may be practical, especially for larger projects.
In particular, they offer few facilities for metaprogramming (using APIs to
manipulate the program itself).
虽然这些规则很好地解释了 Perl 5 的底层对象系统,它们在实际应用时显得捉襟见肘,特
别是对于较大型的项目来说。特别地,它们几乎没有提供元编程(使用 API 操作程序本身)
的组件。

Moose (L<moose>) is a better choice for serious, modern Perl programs larger
than a couple of hundred lines, but you will likely encounter bare-bones Perl 5
OO in existing code.
Moose(L<moose>)对于正式而现代化的、且大于几百行 Perl 程序来说是更好的选择,但你
很可能在现存代码中遇见赤裸裸的 Perl 5 OO。

=end sidebar

Expand All @@ -42,9 +41,8 @@ X<OO; constructor>
X<class method>
X<methods; class>

The default Perl 5 object constructor is a method which creates and blesses a
reference. By convention, constructors have the name C<new()>, but this is not
a requirement. Constructors are also almost always I<class methods>:
默认的 Perl 5 对象构造器是一个创建引用并对其进行 bless 的方法。出于惯例,构造器通
常命名为 C<new()>,但并非一定如此。构造器几乎总是 I<类方法>:

=begin programlisting

Expand All @@ -56,23 +54,17 @@ a requirement. Constructors are also almost always I<class methods>:

=end programlisting

C<bless> takes two arguments, the reference to associate with a class and the
name of a class. You may use C<bless> outside of a constructor or a
class--though abstraction recommends the use of the method. The class name
does not have to exist yet.
C<bless> 接受两个参数,与类相关联的引用以及类的名称。虽然程序抽象建议使用一个单
独的方法来处理,但你仍可以在构造器或类之外使用 C<bless>。类名称不需要事先存在。

By design, this constructor receives the class name as the method's invocant.
It's possible, but inadvisable, to hard-code the name of a class directly. The
parametric constructor allows reuse of the method through inheritance,
delegation, or exporting.
设计上,构造器以被调用者的形式接收类名。直接硬编码类名称也是可能的,但不推荐。
参数式的构造器使得此方法可以通过继承、委托或导出来重用。

X<instance data>
X<OO; instance data>

The type of reference makes no difference when invoking methods on the object.
It only governs how the object stores I<instance data>--the object's own
information. Hash references are most common, but you can bless any type of
reference:
引用的类型对对象上的方法调用没有影响。它只掌控对象如何存储 I<实例数据>────对象
自身的信息。哈希引用最为常见,但你可以 bless 任何类型的引用:

=begin programlisting

Expand All @@ -82,9 +74,8 @@ reference:

=end programlisting

Where classes built with Moose define their own object attributes
declaratively, Perl 5's default OO is lax. A class representing basketball
players which stores jersey number and position might use a constructor like:
Moose 中创建的类由它们自己声明式地定义各自的对象属性,Perl 5 默认的 OO 则非常
宽松。一个存储球衣号和位置、代表篮球运动员的类可能会使用如下构造器:

=begin programlisting

Expand All @@ -99,7 +90,7 @@ players which stores jersey number and position might use a constructor like:

=end programlisting

... and create players with:
……运动员可以这样创建:

=begin programlisting

Expand All @@ -115,7 +106,7 @@ players which stores jersey number and position might use a constructor like:

=end programlisting

Within the body of the class, methods can access hash elements directly:
在类的内部,方法可以直接访问哈希元素:

=begin programlisting

Expand All @@ -127,10 +118,9 @@ Within the body of the class, methods can access hash elements directly:

=end programlisting

Yet so can any code outside of the class. This violates encapsulation--in
particular, it means that you can never change the object's internal
representation without breaking external code or performing hacks--so it's
safer to provide accessor methods:
类之外的方法也可以这样做。这样便违反了封装────特别是,它意味着你绝不能在不
破坏外部代码的情况下改变对象的内部表示,除非投机取巧────因此,保险起见还应
提供访问器方法:

=begin programlisting

Expand All @@ -139,46 +129,40 @@ safer to provide accessor methods:

=end programlisting

Even with two attributes, Moose is much more appealing in terms of code you
don't have to write.
即便只有两个属性,Moose 在那些非必须代码方面显得更具吸引力。

=begin sidebar

Moose's default behavior of accessor generation encourages you to do the right
thing with regard to encapsulation as well as genericity.
Moose 的创建访问器的默认行为鼓励你在注重封装和泛型的情况下编写正确的代码。

=end sidebar

=head2 Method Lookup and Inheritance
=head2 方法查找和继承

X<method dispatch>
X<objects; methods>

Besides instance data, the other part of objects is method dispatch. Given an
object (a blessed reference), a method call of the form:
除实例数据外,对象的另一部分就是方法分派。给定一个对象(一个 bless 后的引用),
如下形式的方法调用:

=begin programlisting

my $number = $joel->number();

=end programlisting

... looks up the name of the class associated with the blessed reference
C<$joel>. In this case, the class is C<Player>. Next, Perl looks for a
function named C<number> in the C<Player> package. If the C<Player> class
inherits from another class, Perl looks in the parent class (and so on and so
on) until it finds a C<number> method. If one exists, Perl calls it with
C<$joel> as an invocant.
……将查找与经 bless 后的引用 C<$joel> 相关联类的名称。在此例中,该类就是 C<Player>。
接下来,Perl 在 C<Player> 包内查找一个名为 C<number> 的函数。如果 C<Player> 类从其
它类继承而来,Perl 也会在父类查找(如此继续)直到它找到 C<number> 方法为止。如果存
在的话,Perl 以 C<$joel> 作为调用物调用它。

X<@ISA>
X<variables; @ISA>

Moose classes store their inheritance information in a metamodel. Each class
of a blessed reference stores information about its parents in a package global
variable named C<@ISA>. The method dispatcher looks in a class's C<@ISA> to
find the names of parent classes in which to search for the appropriate method.
Thus, an C<InjuredPlayer> class might contain C<Player> in its C<@ISA>. You
could write this relationship as:
Moose 类在元模型中存放各自的继承信息。每一个经 bless 后的引用的类将父类信息存放在
一个名为 C<@ISA> 的包全局变量中。方法分派器会在一个类的 C<@ISA> 中查找它的父类,以
在其中搜索合适的方法。因此,一个 C<InjuredPlayer> 类会在其 C<@ISA> 中包含 C<Player>。
你可以这样编写这重关系:

=begin programlisting

Expand All @@ -191,8 +175,7 @@ could write this relationship as:
X<parent>
X<pragmas; parent>

Many existing Perl 5 projects do this, but it's easier and simpler to use the
C<parent> pragma instead:
许多现存的 Perl 5 项目都这样做,但用 C<parent> 编译命令来替代会更容易些:

=begin programlisting

Expand All @@ -207,15 +190,15 @@ X<pragmas; base>

=begin sidebar

Perl 5.10 added C<parent> to supersede the C<base> pragma added in Perl
5.004_4. If you can't use Moose, use C<parent>.
Perl 5.10 为替换增加于 Perl 5.004_4 的 C<base> 编译命令而添加了 C<parent>。如果
你无法使用 Moose,请使用 C<parent>

=end sidebar

X<multiple inheritance>
X<objects; inheritance>

You may inherit from multiple parent classes:
可以从多个父类继承:

=begin programlisting

Expand All @@ -225,24 +208,20 @@ You may inherit from multiple parent classes:

=end programlisting

Perl 5 has traditionally preferred a depth-first search of parents when
resolving method dispatch. That is to say, if C<InjuredPlayer> inherits from
both C<Player> and C<Hospital::Patient>, a method call on an C<InjuredPlayer>
instance will dispatch first to C<InjuredPlayer>, then C<Player>, then any of
C<Player>'s parents before dispatching in C<Hospital::Patient>.
在解析方法分派时,Perl 5 在传统上偏向于对父类使用深度优先搜索。这就是说,如果
C<InjuredPlayer> 从 C<Player> 和 C<Hospital::Patient> 两者继承,一个在 C<InjuredPlayer>
实例上调用的方法将先分派到 C<InjuredPlayer>,然后是 C<Player>,接着经过所有 C<Player>
的父类来到 C<Hospital::Patient>。

X<mro>
X<pragmas; mro>

Perl 5.10 added a pragma called C<mro> which allows you to use a different
method resolution scheme called C3. While the specific details can get complex
in the case of complex multiple inheritance hierarchies, the important
difference is that method resolution will visit all children of a parent before
visiting the parent.
Perl 5.10 增加了一个名为 C<mro> 的编译命令,它允许你另行使用称作 C3 的方法解析策略。
虽然特定的细节可能在处理复杂的多重继承布局时变得复杂,关键的区别是,方法解析过程将
在访问父类之前访问所有的子类。

While other techniques (such as L<roles> and Moose method modifiers) allow you
to avoid multiple inheritance, the C<mro> pragma can help avoid surprising
behavior with method dispatch. Enable it in your class with:
虽然其他技巧(诸如 角色 L<roles> 和 Moose 方法修饰符)允许你避开多重继承,但 C<mro>
编译命令可以帮助你避免方法分派时令人惊讶的行为。可以这样在类中启用:

=begin programlisting

Expand All @@ -252,37 +231,29 @@ behavior with method dispatch. Enable it in your class with:

=end programlisting

Unless you're writing a complex framework with multiple interoperable plugins,
you likely never need to use this.
除非你在编写具有互操作插件的复杂框架,你几乎不会用到它。

=head2 AUTOLOAD

X<AUTOLOAD>
X<objects; AUTOLOAD>
X<methods; AUTOLOAD>

If there is no applicable method in the invocant's class or any of its
superclasses, Perl 5 will next look for an C<AUTOLOAD> function in every class
according to the selected method resolution order. Perl will invoke any
C<AUTOLOAD> it finds to provide or decline the desired method. See L<autoload>
for more details.
如果在调用者及其超类的类定义内没有可用的方法,Perl 5 接下来将按照所选方法解析顺序
在每个类中查找 C<AUTOLOAD> 函数。Perl 会调用它找到的任何 C<AUTOLOAD>,由此提供或
谢绝所需方法。参加 L<autoload> 以获取更多细节。

As you might expect, this can get quite complex in the face of multiple
inheritance and multiple potential C<AUTOLOAD> targets.
如你所想的那样,在面对多重继承和多个候选 C<AUTOLOAD> 目标时会变得很复杂。

=head2 Method Overriding and SUPER
=head2 方法覆盖和 SUPER

You may override methods in the default Perl 5 OO system as well as in Moose.
Unfortunately, core Perl 5 provides no mechanism for indicating your I<intent>
to override a parent's method. Worse yet, any function you predeclare,
declare, or import into the child class may override a method in the parent
class simply by existing and having the same name. While you may forget to use
the C<override> system of Moose, you have no such protection (even optional) in
the default Perl 5 OO system.
与 Moose 中一样,你可以在默认的 Perl 面向对象系统中覆盖方法。不幸的是,Perl 5 核心
并没有提供指出你覆盖父类方法 I<意图> 的机制。更糟糕的是,任何预声明、声明或导入子
类的函数都可能因重名而覆盖父类方法。你可以忘记使用 Moose 的 C<override> 系统,但在
Perl 5 默认的面向对象系统中你根本没有这样(甚至是可选的)一重保护。

To override a method in a child class, declare a method of the same name as the
method in the parent. Within an overridden method, call the parent method with
the C<SUPER::> dispatch hint:
要在子类中覆盖一个方法,只需声明一个和父类方法同名的方法。在覆盖的方法内,你可以通
过 C<SUPER::> 分派指示来调用父类方法:

=begin programlisting

Expand All @@ -295,44 +266,33 @@ the C<SUPER::> dispatch hint:

=end programlisting

The C<SUPER::> prefix to the method name tells the method dispatcher to
dispatch to the named method in a I<parent> implementation. You may pass any
arguments to it you like, but it's safest to reuse C<@_>.
方法名的 C<SUPER::> 前缀告诉方法分派器将此方法分派到 I<父类> 的具名实现。你可以向
其传递任何参数,但最好还是重用 C<@_>。

=begin sidebar

Beware that this dispatcher relies on the package into which the overridden
method was originally compiled when redispatching to a parent method. This is
a long-standing misfeature retained for the sake of backwards compatibility.
If you export methods into other classes or compose roles into classes
manually, you may run afoul of this feature. The C<SUPER> module on the CPAN
can work around this for you. Moose handles it nicely as well.
注意当重分派到父类方法时,这个分派器依赖于覆盖方法最初被编译的包。这长期以来是一个
错误的特性,只是为了向后兼容而保留着。如果你向其它类或角色导出方法或手动合成类和角
色,你会和此项特性正面冲突。CPAN 上的 C<SUPER> 模块可以为你绕过它。Moose 同样能够出
色地处理该问题。

=end sidebar

=head2 Strategies for Coping with Blessed References
=head2 应付经 bless 后引用的策略

Avoid C<AUTOLOAD> where possible. If you I<must> use it, use forward
declarations of your functions (L<functions>) to help Perl know which
C<AUTOLOAD> will provide the method implementation.
可能的话避免使用 C<AUTOLOAD>。如果 I<必须> 用到,你应该用它来转发函数(L<functions>)
定义以帮助 Perl 知道哪个 C<AUTOLOAD> 会提供方法的实现。

Use accessor methods rather than accessing instance data directly through the
reference. This applies even within the bodies of methods within the class
itself. Generating these yourself can be tedious; if you can't use Moose,
consider using a module such as C<Class::Accessor> to avoid repetitive
boilerplate.
使用访问器方法而非直接通过引用访问实例数据。甚至在类内部的方法体内也应该这样做。
由你自己来生成这些方法相当乏味;如果你无法使用 Moose,考虑使用诸如 C<Class::Accessor>
这类模块来避免重复编写样板。

Expect that someone, somewhere will eventually need to subclass (or delegate to
or reimplement the interface of) your classes. Make it easier for them by not
assuming details of the internals of your code, by using the two-argument form
of C<bless>, and by breaking your classes into the smallest responsible units
of code.
准备好某人某时最终将继承你的类(或委托或重新实现接口)。通过不对代码内部细节做出假定、
使用两参数形式的 C<bless> 和把类分割为最小职责单元,可以使得他人的工作更加轻松。

Do not mix functions and methods in the same class.
不要在同一个类里混用函数和方法。

Use a single F<.pm> file for each class, unless the class is a small,
self-contained helper used from a single place.
为每一个类使用单独的 F<.pm> 文件,除非该类是一个仅用于某处的小型自包含辅助类。

Consider using Moose and C<Any::Moose> instead of bare-bones Perl 5 OO; they
can interact with vanilla classes and objects with ease, alleviate almost of
the tedium of declaring classes, and provide more and better features.
考虑使用 Moose 和 C<Any::Moose> 来替代赤裸的 Perl 5 OO;它们可以轻松和 Perl 5 对象系统
的类和对象互动,还减轻了几乎所有因类声明而带来的无趣,同时提供了更多及更好的特性。

0 comments on commit 02d89a9

Please sign in to comment.