Частные переменные в классе Perl Moose

Я начинаю изучать объекты в Perl с помощью Moose.

Я не уверен, что понимаю цель MooseX::Privacy. Учитывать:

use v5.14;

package PA {
    use Moose;
    my $var='private?';
    1;

    sub getVar {
        return $var;
    }
}

package PB {
    use Moose;
    use MooseX::Privacy;

    has 'var' => (
        is => 'rw',
        isa => 'Str',
        default   => 'private?',
        traits => [qw/Private/],
    );
    1;

    sub getVar {
        my $self = shift;
        return $self->var;
    }
}

my $o1= PA->new();
my $o2= PB->new();

say $o1->getVar();
say $o2->getVar();

В обоих классах PA и PB у меня есть частная переменная var. Только в классе PB использую MooseX::Privacy. В чем разница между этими двумя подходами? А зачем использовать MooseX::Privacy?


person Håkon Hægland    schedule 09.04.2014    source источник
comment
Без инициализации из аргументов конструктора, без проверки типов, без принуждения, без наследования, без компоновки, без самоанализа, без возможности добавлять черты, ...   -  person ikegami    schedule 09.04.2014
comment
PA $var статичен, PB - нет. Кроме того, PA вообще использует Moose? Если вы не понимаете преимуществ Moose, весь вопрос спорный.   -  person rutter    schedule 10.04.2014
comment
@ikegami Я говорю только о частных переменных, поэтому я бы все равно не использовал инициализацию конструктора для них?   -  person Håkon Hægland    schedule 10.04.2014
comment
@rutter Я не включил публичные переменные в PA, чтобы сделать пример минимальным ..   -  person Håkon Hægland    schedule 10.04.2014
comment
Точно сказать не могу. У меня нет под рукой Лося для тестирования. Список был больше для того, чтобы дать представление, чем что-либо еще. Ваш вопрос в основном заключается в том, какие преимущества дает Moose?   -  person ikegami    schedule 10.04.2014


Ответы (1)


Если вы ищете конфиденциальность методов в стиле Java, то MooseX :: Privacy будет большим разочарованием. Вот что происходит с конфиденциальностью метода в стиле Java:

/* This file is called Main.java */
public class Main
{
    public class MyParent
    {
        private String message_string ()
        {
            return "Message from %s\n";
        }

        public void print_message ()
        {
            System.out.printf( this.message_string(), "MyParent" );
        }
    }

    public class MyChild extends MyParent
    {
        public String message_string ()
        {
            return "Another message from %s\n";
        }
    }

    public static void main (String[] args)
    {
        Main o = new Main();
        o.run();
    }

    public void run ()
    {
        MyParent c = new MyChild();
        c.print_message();
    }
}

Вы можете скомпилировать и запустить этот пример следующим образом:

$ javac Main.java
$ java Main
Message from MyParent

Обратите внимание на то, что произошло. Родительский класс (MyParent) объявляет message_string() частным методом. Дочерний класс пытается переопределить метод, но получает категорический отказ - дочерний класс вам нечего!

Теперь давайте попробуем эквивалент с Perl и MooseX :: Privacy ...

# This file is called Main.pl
use v5.14;
use strict;
use warnings;

package MyParent {
    use Moose;
    use MooseX::Privacy;

    private_method message_string => sub {
        my $self = shift;
        return "Message from %s\n";
    };

    sub print_message {
        my $self = shift;
        printf($self->message_string(), __PACKAGE__);
    }
}

package MyChild {
    use Moose; extends qw(MyParent);
    use MooseX::Privacy;

    sub message_string {
        my $self = shift;
        return "Another message from %s\n";
    }
}

my $c = new MyChild();
$c->print_message();

Мы можем запустить это так:

$ perl Main.pl
Another message from MyParent

Скажите: ВАЗ?!?!?! Разве message_string не должно быть личным ?! Как, черт возьми, MyChild переопределил метод в MyParent ?!

Дело в том, что MooseX :: Privacy не дает вам ничего близкого к конфиденциальности методов, реализованной в большинстве языков объектно-ориентированного программирования. MooseX :: Privacy просто сродни тому, что вы делаете в вашем методе:

die "GO AWAY!!" unless caller eq __PACKAGE__;

За исключением того, что MooseX :: Privacy увеличивает время выполнения всех вызовов ваших методов.

На самом деле, нет особых причин использовать MooseX :: Privacy. Если вам нужны частные методы, поместите их в лексические переменные. Нравится:

use v5.14;
use strict;
use warnings;

package MyParent {
    use Moose;

    my $message_string = sub {
        my $self = shift;
        return "Message from %s\n";
    };

    sub print_message {
        my $self = shift;
        printf($self->$message_string(), __PACKAGE__);
    }
}

package MyChild {
    use Moose; extends qw(MyParent);

    sub message_string {
        my $self = shift;
        return "Another message from %s\n";
    }
}

my $c = new MyChild();
$c->print_message();

Теперь запустим его:

$ perl Main2.pl
Message from MyParent

Аллилуйя !! У нас есть настоящий частный метод!

Итак, у вас могут быть частные методы без MooseX :: Privacy, и они работают лучше (и быстрее), чем MooseX :: Privacy.

Но как насчет частных атрибутов? Что ж, у меня есть небольшой модуль на CPAN, который может вам помочь: Lexical :: Accessor. Это небольшой инструмент, который создает для вас атрибут с хранением «наизнанку» (т.е. значение атрибута не сохраняется в благословенном хешрефе объекта) и устанавливает для него аксессоры в лексических переменных (точно так же, как частный $get_message способ выше).

Во всяком случае, это мое мнение о MooseX :: Privacy.

person tobyink    schedule 09.04.2014
comment
Спасибо за интересный ответ! Что бы произошло, если бы метод print_message был определен в дочернем классе вместо родительского? (Или если это было отменено у ребенка?) - person Håkon Hægland; 10.04.2014
comment
Если print_message определен в MyChild, он всегда может вызвать get_message, который также определен в MyChild (независимо от того, какая конфиденциальность выбрана для get_message). Если print_message определен в MyChild, но get_message является частным методом, определенным в MyParent, то в Java (и с использованием моей лексической техники) он не может вызвать get_message, потому что не может даже увидеть, что get_message существует! С MooseX :: Privacy он может его видеть и вызывать, но при этом генерируется исключение. - person tobyink; 10.04.2014