Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > Как правильно передавать переменные в объекты?


Автор: Infod 31.3.2007, 16:28
Есть класс MainClass.pm

создаем объект
$main = new MainClass;

присваиваем объекту константу
$main->{myconst} = "Something";

В главном пакете есть много разных подпакетов вида 
MainClass::SubClass1
MainClass::SubClass2

объекты создаются вида:
$main->{obj1} = new MainClass::SubClass1;

также есть вида:
MainClass::SubClass1::SubSubClass1

и есть класс MainClass::Uni::LWP.pm

так вот, этот универсальный класс используется многими другими подклассами.
и при создании объекта
$ua = new MainClass::Uni::LWP;

в него нужно передать константу $main->{myconst} из главного класса

Как это сделать, если объект LWP создается во всех классах?
Пока приходят в голову глобальные переменные (фи smile ) или передавать эту константу при создании объектов - но это муторно

Помогите плз, я не очень силен в ООП, подозреваю, что ответ должен быть простой
Сорри, если сумбурно

Спасибо

Автор: Nab 31.3.2007, 17:42
У меня реализован такой механизм.
Так как весь основной функционал реализуется через методы ядра, и плагины добавляют объекту ядра дополнительный функционал тоже в виде методов, то объект ядра у меня сквозной: передаеться как параметр всем объектам - плагинам при создании и доступен из любой точки приложения.
Код

$main->{obj1} = MainClass::SubClass1->new($main);
# в методе new MainClass::SubClass1
package MainClass::SubClass1;
use Scalar::Util;
sub new {
    $class = shift;
    bless $self, $class;
    $self->{'main'} = shift;

    Scalar::Util::weaken( $self->{'main'} )
        if ref $self->{'main'};    # weaken circular reference

    $self->{'ua'} = MainClass::Uni::LWP->new($self->{'main'}->{myconst});
}

И еще, как правило напрямую к объекту как к хешу не стоит обращаться, нужно реализовать доступ к свойствам через методы, тогда контролировать легче будет кто где и чего изменяет...

Автор: Infod 31.3.2007, 19:35
Цитата

Так как весь основной функционал реализуется через методы ядра, и плагины добавляют объекту ядра дополнительный функционал тоже в виде методов, то объект ядра у меня сквозной: передаеться как параметр всем объектам - плагинам при создании и доступен из любой точки приложения.
Выделить всё


А есть ли более красивые способы? И сильно ли повлияет передача объекта во все другие объекты на использование памяти и быстродействие?

Цитата

И еще, как правило напрямую к объекту как к хешу не стоит обращаться, нужно реализовать доступ к свойствам через методы, тогда контролировать легче будет кто где и чего изменяет...


Я так и делаю, в примере для простоты написал

Автор: Nab 31.3.2007, 19:57
Цитата(Infod @  31.3.2007,  19:35 Найти цитируемый пост)
А есть ли более красивые способы? И сильно ли повлияет передача объекта во все другие объекты на использование памяти и быстродействие?

Передается не объект а ссылка на него... а она у вас будет так или иначе передаваться, не важно каким способом вы получите доступ к нужному параметру... А вообще, это зависит от изначальной архитектуры приложения, если основной способ передачи параметров другой, то делайте пожалуй однотипно, чтоб самому не путаться потом...

Автор: korob2001 31.3.2007, 20:07
Цитата

так вот, этот универсальный класс используется многими другими подклассами.
и при создании объекта
$ua = new MainClass::Uni::LWP;

в него нужно передать константу $main->{myconst} из главного класса

Можно попробовать, в основном классе. Создать поле, в котором и будет храниться уже созданный объект класса MainClass::Uni::LWP. Создавать этот объект можно в конструкторе основного класса. Затем создать метод, который будет при необходимости возвращать уже готовый объект, всем подклассам, которые его используют или наследуют от него.
В итоге у нас в памяти будет только один объект, с которым и будут работать все подклассы и наш основной класс. Разумеется такой подход не всегда уместен, но если при создании объекта используются одни и те же данные, то он вполне оправдан.

Хотя возможно я не совсем понял условие задачи. 

Автор: Infod 31.3.2007, 20:35
Цитата

Можно попробовать, в основном классе. Создать поле, в котором и будет храниться уже созданный объект класса MainClass::Uni::LWP. Создавать этот объект можно в конструкторе основного класса. Затем создать метод, который будет при необходимости возвращать уже готовый объект, всем подклассам, которые его используют или наследуют от него.


Об этом я тоже сразу подумал, правда мне совсем не понятно, как это реализовать.  smile 

Набросал пример, если не трудно, можете пояснить на этом коде?

Код


use MainClass;

my $obj = new MainClass;
$obj->{my_constant} = "some_value";

$obj->

package MainClass;

sub new  { ... }

  sub main_func  {
     my $main = new MainClass::SubClass1;
     $main->process_task;
  }

# Вот такой "универсальный" метод создавать?
sub ua  {
  my ($self) = shift;
  my $ua = new MainClass::Uni::LWP(my_const => $self->{my_constant});

  return $ua;
}

package MainClass::SubClass1  {
  sub new { ... }

  sub process_task  {
    my $self = shift;

    my $process = new MainClass::SubClass2;
  }
}

package MainClass::SubClass2  {
  sub new { ... }

  sub parse_page  {
    my $self = shift;
    
    my $ua = new MainClass::Uni::LWP;  # Вот как сюда передать константу?
  }
}



т.е. не понятно, как созданным объектам получить доступ к объекту $obj. Или я создаю их неправильно?

Автор: nitr 31.3.2007, 21:43
Цитата(Nab @  31.3.2007,  17:42 Найти цитируемый пост)
И еще, как правило напрямую к объекту как к хешу не стоит обращаться, нужно реализовать доступ к свойствам через методы, тогда контролировать легче будет кто где и чего изменяет...

сказано... 

Автор: tishaishii 31.3.2007, 22:02
Как получится - так и "правильно".

Автор: korob2001 31.3.2007, 22:28
Ну так через конструкторы и передавай свою константу:
Код

my $obj = new MainClass(my_const => "Bla, bla, bla");


package MainClass;

sub new  {
    my $check = shift;
    my $class = ref($check) ||  $check;
    my $self = {
        my_const => "default_value", @_
    };
    return bless($self, $class);
}

sub main_func  {
     my $main = new MainClass::SubClass1(my_const => $self->{my_const});  # Передаём константу дальше
     $main->process_task;
}

sub ua  {
  my ($self) = shift;
  my $ua = new MainClass::Uni::LWP(my_const => $self->{my_constant});

  return $ua;
}

package MainClass::SubClass1  {
  sub new {
      my $check = shift;
      my $class = ref($check) ||  $check;
      my $self = {
          my_const => "default_value", @_
      };
      return bless($self, $class);
  }

  sub process_task  {
    my $self = shift;

    my $process = new MainClass::SubClass2(my_const => $self->{my_const}); # Передаём константу дальше
  }
}

package MainClass::SubClass2  {
  sub new {
      my $check = shift;
      my $class = ref($check) ||  $check;
      my $self = {
          my_const => "default_value", @_
      };
      return bless($self, $class);
  }

  sub parse_page  {
    my $self = shift;
    
    my $ua = new MainClass::Uni::LWP($self->{my_const});  # Вот как сюда передать константу? ( Передаём константу ещё дальше).
  }
}

Константу мы передали до места назначения, но код этот глюковатый. Так как над ним можно, а главное нужно, хорошенько подумать. Для этого либо тебе нужно чётко изложить, цель всего, что написано выше, либо перейти на примеры попроще.

Ты помоему сильно увлекаешься созданием методов-фабрик, т.е. в методе ты создаешь новый объект. Вот здесь например:
Код

sub main_func  {
     my $main = new MainClass::SubClass1(my_const => $self->{my_const});  # Передаём константу дальше
     $main->process_task;
}

sub ua  {
  my ($self) = shift;
  my $ua = new MainClass::Uni::LWP(my_const => $self->{my_constant});

  return $ua;
}

Перед тем как создавать такую фабрику объектов, нужно подумать:
А действительно нужно создавать новый объект при каждом вызове метода main_func() или ua()? Или же можно создать этот объект один раз, в конструкторе или методе INIT, при созданнии текущего объекта, сохранить её в тот же анонимный хеш и пользоваться этой ссылкой везде, где объект не обязательно должен быть новым?

Автор: Infod 31.3.2007, 23:17
Цитата

Ну так через конструкторы и передавай свою константу:


Это ж неудобно. А если констант или переменных несколько, и каждому объекту нужны не все они? Передавать хеш с параметрами не предлагать smile

Цитата

А действительно нужно создавать новый объект при каждом вызове метода main_func() или ua()?


Это я в примере написал, чтобы показать, насколько бывает неудобно таскать эту константу по объектам. smile 

А цель у меня была - понять, как лучше всего обмениваться параметрами между объектами.
Значит только передавать ссылку на главный объект или передавать каждому объекту нужные параметры через конструктор?

Автор: korob2001 1.4.2007, 04:07
В принципе, можно передавать не только число или строку, можно создатьвать объект любого класса и передать его, твоему классу. Главное что бы твой класс был готов корректно работать с этим объектом. Как класс это будет делать, конечного программиста, использующего его, вообще не должно волновать. Он читает документацию, изучает интерфейс класса и работает с его открытыми методами и полями.

Так же не стоит забывать о наследовании, если ответ на вопрос: "Является?", положительный. Например:
Пудель, является Собакой? Да. Значит класс Pudel может быть подклассом класса Dog.
Собака, является Животным? Да. Значит класс Dog может быть подклассом класса Animal.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)