[英]Perl inheritance - Subroutine override
Is there a way to override sub a
in class_1_1
and class_2_1
with a new behavior(same for both classes) without adding the overridden method to both class_1_1
and class_2_1
?有没有办法用新行为(两个类相同)覆盖class_1_1
和class_2_1
sub a
而不将覆盖的方法添加到class_1_1
和class_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;
One tailor-made solution is to add a role for the wanted behavior.一种量身定制的解决方案是为所需行为添加角色。
Here is an example with native OO code, using stand-alone Role::Tiny for roles这是一个带有本机 OO 代码的示例,对角色使用独立的Role::Tiny
use warnings;
use strict;
use SomeClass;
my $obj = SomeClass->new;
$obj->a_method;
The class SomeClass.pm
类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;
This role can be added to other classes as well, by adding the use
statement and the line with 'AddedRoles';
通过添加use
语句和with 'AddedRoles';
的行with 'AddedRoles';
也可以将此角色添加到其他类with 'AddedRoles';
to them, regardless of their inheritance relationships.对他们来说,不管他们的继承关系如何。 See the docs for ways to fine tune the process.有关微调过程的方法,请参阅文档。
The package with the roles, AddedRoles.pm
包含角色的包, 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;
The Role::Tiny
need be installed (which has no dependencies).需要安装Role::Tiny
(没有依赖项)。 To replace a method that is defined in the class that consumes the role we need a method modifier around
, † provided by Class::Method::Modifiers , so that is an additional dependency.要替换在使用角色的类中定义的方法,我们需要一个方法修饰符around
, †由Class::Method::Modifiers 提供,因此这是一个额外的依赖项。
Roles are often compared to inheritance, and claimed to provide a nicer and lighter alternative since inheritance is normally "baked" into the whole class hierarchy etc. However, inheritance generally specializes behavior while roles are clearly more flexible;角色经常被比作继承,并声称提供了一个更好、更轻松的替代方案,因为继承通常“烘焙”到整个类层次结构等中。然而,继承通常专门化行为,而角色显然更灵活; they add or modify behavior (or can specialize for that matter).他们添加或修改行为(或可以专门针对该问题)。 I rather see roles fitting nicely somewhere between inheritance and composition.我宁愿看到角色在继承和组合之间很好地匹配。
Note that with roles we can have a near equivalent of multiple inheritance, with almost none of its formidable (and forbidding) headaches.请注意,对于角色,我们可以拥有几乎等同于多重继承,几乎没有它令人生畏(和令人生畏)的麻烦。
The bare-bones example above demonstrates the use of Role::Tiny
on its own.上面的简单示例演示了Role::Tiny
的使用。 But roles are better utilized along with Moose
or Moo
frameworks, using Moose::Role or Moo:Role .但是使用Moose::Role或Moo:Role可以更好地利用角色与Moose
或Moo
框架一起使用。
I would absolutely recommend to look into these frameworks.我绝对建议研究这些框架。 I strongly believe in the value of learning well how to use the Perl's native OO system, but once one has that under their belt it'd be a shame to not try Moose
or Moo
.我坚信学习如何使用 Perl 的原生 OO 系统的价值,但是一旦有人掌握了这一点,不尝试Moose
或Moo
将是一种耻辱。
† In this particular question though the method to override is inherited from another class and in that case there is no need for a modifier. †在这个特定问题中,虽然要覆盖的方法是从另一个类继承的,但在这种情况下不需要修饰符。 From "Role Composition" in docs来自文档中的“角色构成”
If a method is already defined on a class, that method will not be composed in from the role.如果一个方法已经在一个类上定义,该方法将不会从角色中组合。 A method inherited by a class gets overridden by the role's method of the same name, though.但是,由类继承的方法会被角色的同名方法覆盖。
So in the case of this question it is enough to normally define a sub in the roles package所以在这个问题的情况下,通常在角色包中定义一个子就足够了
# In the package that defines roles (like 'AddedRoles' above)
sub a_method { say "From an overriding role ", __PACKAGE__ }
and when this role is consumed by a class which inherits a_method
, like class_1_1
in the question, the method does get overridden by this one.当这个角色被一个继承a_method
的类消耗时,比如class_1_1
中的class_1_1
,该方法确实被这个方法覆盖。
Note that if a method is defined in the class itself (not inherited) then a role defined as a normal sub
is quietly ignored (it won't override the method and it won't warn or such).请注意,如果在类本身中定义了一个方法(不是继承的),那么定义为普通sub
的角色将被悄悄忽略(它不会覆盖该方法,也不会发出警告等)。
On the other hand, around
overrides a method in either case (inherited or defined in the class), but cannot add a method that isn't there at all (and throws an exception if that is attempted).另一方面,在任何一种情况下, around
覆盖一个方法(在类中继承或定义),但不能添加根本不存在的方法(如果尝试,则会抛出异常)。
You can do it with multiple inheritance:您可以使用多重继承来做到这一点:
#!/usr/bin/perl
use strict;
use warnings;
package class_0;
sub new {
my ($class, $foo) = @_;
return bless{foo=>$foo}, $class;
}
sub a {
my $self=shift;
print 'a class_0 foo=' . $self->{foo} . "\n";
}
sub b {
my $self=shift;
print 'b class_0 foo=' . $self->{foo} . "\n";
}
package new_a;
sub a {
my $self=shift;
print 'a new_a foo=' . $self->{foo} . "\n";
}
package class_1;
use parent -norequire, 'class_0';
sub b {
my $self=shift;
print 'b class_1 foo=' . $self->{foo} . "\n";
}
package class_1_1;
use parent -norequire, 'new_a', 'class_1';
package class_2;
use parent -norequire, 'class_0';
sub b {
my $self=shift;
print 'b class_2 foo=' . $self->{foo} . "\n";
}
package class_2_1;
use parent -norequire, 'new_a', 'class_2';
package main;
# example usage
my $c0 = class_0->new(1);
my $c1 = class_1->new(2);
my $c2 = class_2->new(3);
my $c11 = class_1_1->new(4);
my $c21 = class_2_1->new(5);
print "-- a class_0 b class_0\n";
$c0->a; $c0->b;
print "-- a class_0 b class_1\n";
$c1->a; $c1->b;
print "-- a class_0 b class_2\n";
$c2->a; $c2->b;
print "-- a new_a b class_1\n";
$c11->a; $c11->b;
print "-- a new_a b class_2\n";
$c21->a; $c21->b;
Output:输出:
-- a class_0 b class_0
a class_0 foo=1
b class_0 foo=1
-- a class_0 b class_1
a class_0 foo=2
b class_1 foo=2
-- a class_0 b class_2
a class_0 foo=3
b class_2 foo=3
-- a new_a b class_1
a new_a foo=4
b class_1 foo=4
-- a new_a b class_2
a new_a foo=5
b class_2 foo=5
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.