Perl 继承 - 子程序覆盖

Jea*_*ean 3 perl inheritance

有没有办法来覆盖sub aclass_1_1,并class_2_1用新的行为(两者相同的类)不增加重写的方法都class_1_1class_2_1

package class_0
    sub a
    sub b
1;

package class_1 
    use parent 'class_0'
    sub b
1;

package class_2
    use parent 'class_0'
    sub b
1;

package class_1_1
    use parent 'class_1'
1;

package class_2_1
    use parent 'class_2'
1;  
Run Code Online (Sandbox Code Playgroud)

zdi*_*dim 7

一种量身定制的解决方案是为所需行为添加角色

这是一个带有本机 OO 代码的示例,对角色使用独立的Role::Tiny

use warnings;
use strict;

use SomeClass;

my $obj = SomeClass->new;

$obj->a_method;
Run Code Online (Sandbox Code Playgroud)

班上 SomeClass.pm

package SomeClass;

use warnings;
use strict;
use feature 'say';

use Role::Tiny::With;  # To "consume" a role. Comes with Role::Tiny

# Consume roles from "AddedRoles.pm"
# That may add or require methods, or override the ones here
with 'AddedRoles';     

sub new { bless { }, $_[0]] }

sub a_method { say "From ", __PACKAGE__ }

1;
Run Code Online (Sandbox Code Playgroud)

也可以将这个角色添加到其他类中,方法是向它们添加use语句和行with 'AddedRoles';,而不管它们的继承关系如何。有关微调过程的方法,请参阅文档。

带有角色的包, AddedRoles.pm

package AddedRoles;

use feature 'say';  # we get strict and warnings from the package but not this

use Role::Tiny;

# Require that consumers implement methods; Add a method
#require method_1, method_2;    
#sub added_method { say "Adding functionality to consumers" }

# Replace "a_method" in a consumer
around a_method => sub { say "From an overriding role ", __PACKAGE__ } 

1;
Run Code Online (Sandbox Code Playgroud)

Role::Tiny需要进行安装(没有依赖)。要替换在使用角色的类中定义的方法,我们需要一个方法修饰符 aroundClass::Method::Modifiers 提供,因此这是一个额外的依赖项。

角色经常被比作继承,并声称提供了一个更好、更轻松的替代方案,因为继承通常“烘焙”到整个类层次结构等中。然而,继承通常专门化行为,而角色显然更灵活;他们添加或修改行为(或可以专门针对该问题)。我宁愿看到角色在继承和组合之间很好地匹配。

请注意,对于角色,我们可以拥有几乎等同于多重继承,几乎没有它令人生畏的(和令人生畏的)头痛。

上面的基本示例演示了Role::Tiny其自身的使用。但是使用Moose::RoleMoo:Role可以更好地利用角色与MooseMoo框架。

我绝对建议研究这些框架。我坚信学习如何使用 Perl 的原生 OO 系统的价值,但是一旦有人掌握了这一点,不尝试MooseMoo.


在这个特定问题中,虽然要覆盖的方法是从另一个类继承的,但在这种情况下不需要修饰符。来自文档中的“角色构成”

如果一个方法已经在一个类上定义,该方法将不会从角色中组合。但是,由类继承的方法会被角色的同名方法覆盖。

所以在这个问题的情况下,通常在角色包中定义一个子就足够了

# In the package that defines roles (like 'AddedRoles' above)
sub a_method  { say "From an overriding role ", __PACKAGE__ } 
Run Code Online (Sandbox Code Playgroud)

当这个角色被一个继承 的类消耗时a_method,就像class_1_1在问题中一样,这个方法确实被这个方法覆盖了。

请注意,如果在类本身中定义了一个方法(未继承),那么定义为正常的角色将sub被悄悄忽略(它不会覆盖该方法,也不会发出警告等)。

另一方面,around在任何一种情况下都覆盖一个方法(在类中继承或定义),但不能添加根本不存在的方法(如果尝试会抛出异常)。