Xpoint
   [напомнить пароль]

How to redefine parent-class's private method by a child-class?

Метки: [без меток]
2006-10-12 18:24:42 [обр] Игорь Лебедев(0/7)[досье]

Здравствуйте /.*/!

Расшифрую тему.

Представьте, что есть некий веб-фрэймфорк, в состав которого входит класс (package) AbstractClass. Этот класс предпринимает попытку быть универсальным для каких-то типовых задач (в моем случае это будет ...::Model::Entity).

Есть приложение realapp.pl, к нему есть 2 класса RealClass1 и RealClass2 - они потомки AbstractClass. Эти классы описывают реальные объекты, и имеют некоторые отличия от унверсальной абстракции.

AbstractClass имеет abstractMethod, который в свою очередь использует someDefaultMethod.
Потомки AbstractClass хотят сохраняя все черты родителя, в том числе общий алгоритм abstractMethod, вместо someDefaultMethod определить свои методы.

Вопрос - как это делается?
Как для созданного объекта переопределить метод, который он получил по наследству от класса AbstractClass?

Приводимый мною пример неправильный, классы-потомки пытаются переопределить метод для абстрактного класса, а не метод объекта. Как иначе - я х. его з.

Читал Learning Perl и Programming Perl. Ответа не нашел.

Результат работы realapp.pl:

Test: 60.
Test: 60.

+ ругань perl warnings.
А хочется иметь результат такой:

Test: 45.
Test: 60.

Привожу код файлов:


AbstractClass.pm

#!/usr/bin/perl

use strict;
use warnings;

package AbstractClass;
require Exporter;

our @ISA    = "";
our @EXPORT = "
";

sub new {
   my $self = {};
   bless $self;
   return $self;
};

sub abstractMethod {
   my $self = shift @_;
   my %args = @_;
   return $self -> someDefaultMethod(foo => $args{foo});
};

sub someDefaultMethod {
   my $self = shift @_;
   my %args = @_;
   return $args{foo} * 2;
}

sub test {
   my $self = shift @_;
   my %args = @_;
   print "Test: " . $self -> abstractMethod(foo => $args{foo}) . ".\n";
};

RealClass1.pm

#!/usr/bin/perl

use strict;
use warnings;

package RealClass1;
require Exporter;

our @ISA    = "AbstractClass";
our @EXPORT = "
";

sub AbstractClass::someDefaultMethod {
   my $self = shift @_;
   my %args = @_;
   return $args{foo} * 3;
};

RealClass2.pm

#!/usr/bin/perl

use strict;
use warnings;

package RealClass2;
require Exporter;

our @ISA    = "AbstractClass";
our @EXPORT = "
";

sub AbstractClass::someDefaultMethod {
   my $self = shift @_;
   my %args = @_;
   return $args{foo} * 4;
};

realapp.pl

#!/usr/bin/perl

use strict;
use warnings;

use AbstractClass;
use RealClass1;
use RealClass2;

my $object1 = RealClass1 -> new;
my $object2 = RealClass2 -> new;

$object1 -> test (foo => 15);
$object2 -> test (foo => 15);

Прошу помощи.

спустя 6 часов [обр] Сергей Чернышев(0/589)[досье]

Все-таки метод абстрактного класса не private - иначе его нельзя переопределить - для детей его просто не существует (это безотносительно к перлу, а просто про ООП).

Во вторых, у вас, похоже, не правильный метод new в классе AbstractClass - он должен bless-ать в имя класса для которого он был вызван, а не в котором он был определен, поэтому у вас оба $object1 и object2 на самом деле являются instance-ами AbstractClass, а не RealClass1 и RealClass2, соответственно.

       bless REF,CLASSNAME
       bless REF
               This function tells the thingy referenced by REF that it is now
               an object in the CLASSNAME package. If CLASSNAME is omitted,
               the current package is used
. Because a "bless" is often the
               last thing in a constructor, it returns the reference for con-
               venience. Always use the two-argument version if the function
               doing the blessing might be inherited by a derived class. See
               perltoot and perlobj for more about the blessing (and bless-
               ings) of objects.

               Consider always blessing objects in CLASSNAMEs that are mixed
               case. Namespaces with all lowercase names are considered
               reserved for Perl pragmata. Builtin types have all uppercase
               names, so to prevent confusion, you may wish to avoid such
               package names as well. Make sure that CLASSNAME is a true
               value.

               See "Perl Modules" in perlmod.

То-есть new нужно переписать так:

sub new {
   my $class = shift;
   my $self = {};
   bless $self, $class;
   return $self;
};

Ну и методы нужно определять в child-е, а не в parent-e и, следовательно не нужно писать название класса, а просто для RealClass1.pm писать:

sub someDefaultMethod {
   my $self = shift @_;
   my %args = @_;
   return $args{foo} * 3;
};

Таков мой не очень глубокий опыт познания перлового ООП - возможно я где-то не совсем точен.

спустя 54 секунды [обр] Alexander O(30/469)[досье]

Игорь Лебедев[досье]

  1. в AbstractClass заменить new например на
sub new {
    my $class = shift;
    my $self  = {};
    bless ($self, $class);
    return $self;
}

Иначе new всегда будет создавать объект класса AbstractClass, даже при вызове RealClass1 -> new;
perldoc -f bless
perldoc perltoot

  1. В RealClass1 и RealClass2 не надо переопределять AbstractClass::someDefaultMethod, а нужно просто определить свои someDefaultMethod. Т.е. достаточно убрать префикс AbstractClass::
  1. Для модулей (.pm) строка #!/usr/bin/perl не нужна.
  1. Последней строкой модуля (.pm) хорошо бы иметь 1;
спустя 5 минут [обр] Сергей Чернышев(0/589)[досье]
Alexander O[досье]
Как мы синхронно, однако... ;)
спустя 11 часов [обр] Игорь Лебедев(0/7)[досье]
Сергей Чернышев[досье]
Alexander O[досье]
Все получилось.
Спасибо!
Powered by POEM™ Engine Copyright © 2002-2005