首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在perl中,如何在多个包中编写方法?

在perl中,如何在多个包中编写方法?
EN

Stack Overflow用户
提问于 2015-03-25 19:30:39
回答 3查看 92关注 0票数 1

我正在编写一个perl类,为了这个问题,我将把它称为“学生”。学生类会有很多方法,为了整洁和效率,我不想把它们都放在一个源文件中。

假设Student.pm是package Student,包含sub new (构造函数),而say /Enrol.pm是package Student::Enroll,包含sub enroll (一个方法)。我写的sub enroll是这样的:

代码语言:javascript
复制
sub enroll
{
    my ($student) = @_;

    # do something;
    return;
}

*Student::enroll = \&enroll;

在我的主程序中,我可以编写my $student = new Student()$student->enroll()。这是可行的,但它不透明。它有什么我忽略的缺点吗?

我还没有尝试从package::Enroll导出enroll到package中。这不是我想要的,因为那样的话,我需要在学生包中写use Student::Enroll,我不想这样做。有些程序需要学生包,但不需要学生::登记。

是否有一种更好、更干净的方法来编写sub enroll /Enrol.pm,从而使它成为一个学生方法?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-03-25 19:40:38

可以在sub声明中使用包限定符。

代码语言:javascript
复制
package Student::Enroll;
...
sub foo { ... }   # Student::Enroll::foo
sub Student::enroll { ... }  # Student::enroll, not Student::Enroll::enroll
...

当然,如果Student::enrollStudent/Enroll.pm中的唯一定义,以及某些程序需要Student::enroll函数,那么该程序将不得不加载Student/Enroll.pm和所有的Student::Enroll包。

票数 2
EN

Stack Overflow用户

发布于 2015-03-25 23:49:37

它可以很容易地用自编方法来完成。

代码语言:javascript
复制
package Student::Enroll;
use strict;
use warnings;
use v5.14;

sub enroll { say "Good luck $_[1]";  }

1;

新版本:

代码语言:javascript
复制
package Student;
use strict;
use warnings;
use v5.14;
use Carp qw/croak/;

{
    my $_additional_methods = {
        enroll => undef
    };

    sub _can_access { 
        exists $_additional_methods->{$_[0]} 
    }
}

sub new { bless {}, shift }

# Subroutine AUTOLOAD will be called always 
# when someone calls a method (a subroutine) which 
# isn't present in this module.
# In our case "enroll" will be called from AUTOLOAD
# only one and next time of calling it will be called
# directly as a normal method of the class since
# we create a typeglob ref for it.
sub AUTOLOAD {
    no strict 'refs';

    our $AUTOLOAD; # in this global variables are kept
                   # the full name of a called method

    my $package_method = $AUTOLOAD;                   

    # making up the full method name
    $AUTOLOAD =~ s/(.*)::(\w+)$/Student::Enroll::$2/;

    my $package = $1;
    my $method  = $2;

    if ( _can_access($method) ) { 

        eval 'use Student::Enroll;'; # loading of the necessary class

        &$AUTOLOAD(@_); # calling the method from Student::Enroll class

        no warnings 'redefine';                    
        *{$package_method} = \&AUTOLOAD;
    } else {
        croak "Can't locate object method '$method' via package '$package'";
    }
}

package main;
use strict;
use warnings;

my $student = Student->new;
$student->enroll('David');
$student->enroll('David');
$student->enoll('David');

旧版本:

代码语言:javascript
复制
package Student;
use strict;
use warnings;
use v5.14;

sub new { bless {}, shift }

# Subroutine AUTOLOAD will be called always 
# when someone calls a method (a subroutine) which 
# isn't present in this module (enroll in our case)
sub AUTOLOAD {
    no strict 'refs';

    our $AUTOLOAD; # in this global variables are kept
                   # the full name of a called method

    eval 'use Student::Enroll;'; # loading of the necessary class

    # making up the full method name
    $AUTOLOAD =~ s/.*::(\w+)$/Student::Enroll::$1/;
    &$AUTOLOAD; # calling the method from Student::Enroll class
                # Note: array @_ of args is passed automatically
}

package main;
use strict;
use warnings;

my $student = Student->new;
$student->enroll('David');
票数 1
EN

Stack Overflow用户

发布于 2015-03-26 15:56:45

首先,我建议以“现代Perl”的方式开始编程,远离老式的Perl5祝福对象散列.

代码语言:javascript
复制
use Moose;

这是一个适合Perl的OO系统,借用自Perl6。

当你的课变得“大”的时候,是时候重新考虑什么是真正进入课堂的,什么是不应该出现的。有些属性和方法实际上可能是非常通用的,并且可以从超类继承。但是Moose (和Moo)也有“角色”,这种行为可以添加到另一个类之上。

让我展示一下我的“学生”班是什么样子的:

代码语言:javascript
复制
package College::Student;

use Moose;

extends 'Person';

has 'student_registration_number' => (
    is       => 'ro',
    isa      => 'Int',
    required => 1,
);

with 'College::Enrolment';

1;

正在发生的事情:

第01行:声明包的名称,College::Student,这是一个单独的名称空间,用于与学院相关的内容。

第03行:自然use Moose;

第05行:我们使用另一个类Person,并将其用作基类。现在,在本例中,我确实创建了一个College::Student类,一个比通用Person类更具体的类(也不是在College命名空间中)。

第07行:特定于这个College::Student类,这里只使用一个student_registration_number,它是一个整数类型的只读属性,是必需的。

第12行:使用角色College::Enrolment,我们希望学生有更多的行为--这样它就可以注册一门课程,并且需要什么方法和属性才能做到这一点,这在这里并不重要,我们在这里想要做的就是它能做到这一点。

现在来看一下“学院::招生”课程的内部情况:

代码语言:javascript
复制
package College::Enrolment;

use Moose::Role;

sub enroll {
    my $self = shift; # a person
    my $args = {@_};
    print 
        $self->name,
        " is being enrolled into: ",
        $args->{'course'}->course_title,
        "\n",
    ;   
};

sub un_enroll {
};

1;

第01行:一个很好的名称空间,同样与学院有关。

第03行:这是一个驼鹿::角色,可以应用于其他对象.你不能实例化这些!

线05:啊..。显然,有一个enroll实例方法,

第16行:以及一个un_enroll实例方法。

为了完整起见,基类Person看起来非常基本,不适合学生。

代码语言:javascript
复制
package Person;

use Moose;

has name => (
    is       => 'ro',
    isa      => 'Str',
    required => 1,
);

has date_of_birth => (
    is       => 'ro',
    isa      => 'DateTime',
    required => 1,
);

1;

还可以对类似于College::Professor的类进行扩展:

代码语言:javascript
复制
package College::Professor;

use Moose;

extends 'Person';

has 'employee_number' => (
    is       => 'ro',
    isa      => 'Int',
    required => 1,
);

with 'College::Enrolment'

1;

现在,College::Professor是一个Person,但是它没有College::Enrolment角色。

如果您愿意的话,也可以很容易地为College::GuestStudent创建一个类,它可能没有注册号,但是需要能够注册--使用相同的角色。

在这里踢驼鹿的力量..。

与其创建庞大的类,不如尝试拆分尽可能多的角色,这些角色是方法及其属性的逻辑组合。这使得它更易于维护和测试。很快,您将看到角色是构建类的一种更符合逻辑的方法,而不是尝试进行继承--或者更糟糕的是,多继承。

哦..。缺少的东西:

代码语言:javascript
复制
use strict;
use warnings;

use College::Student;
use College::Course;

use DateTime::Format::ISO8601;

my $study = College::Course->new(
    course_title  => "French for beginners"
);

my $pupil = College::Student->new(
    name          => "John Doe",
    date_of_birth => DateTime::Format::ISO8601->parse_datetime("2001-07-10"),
    student_registration_number
                  => '123456',

);

$pupil->enroll( course => $study );


__END__

别忘了读穆斯的故事

2014/07-object-oriented-perl.html

http://www.theperlreview.com/articles/moose.html

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29264837

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档