Это может оказаться смущающе глупым вопросом, но лучше, чем потенциальное создание смущающе глупого кода.:-) Это - вопрос о дизайне OO, действительно.
Скажем, у меня есть класс объекта 'Foos', который представляет ряд динамических элементов конфигурации, которые получены путем запросов команды на диске, 'mycrazyfoos-getconfig'. Скажем, то, что существует две категории поведения, которое я хочу объекты 'Foos' иметь:
Существующие: каждый, запроса, которые существуют в выводе команды, который я просто упомянул (/usr/bin/mycrazyfoos-getconfig'. Сделайте модификации к существующим через выход из оболочки команд.
Создайте новые, которые не существуют; новый 'crazyfoos', с помощью сложного набора /usr/bin/mycrazyfoos
команды и параметры. Здесь я действительно просто не запрашиваю, но на самом деле выполняю набор системы () команды. Влияние на изменения.
Вот моя структура класса:
Foos пакета, который имеет новое ($hashref-> {имя => 'myfooname') конструктор, который берет 'crazyfoo ИМЯ' и затем запрашивает существование того ИМЕНИ, чтобы видеть, существует ли он уже (путем выхода из оболочки и выполнения команды mycrazyfoos выше). Если это, crazyfoo уже существует, возвращают Foos:: Существующий объект. Любые изменения в этом объекте требуют выхода из оболочки, выполнения команд и получения подтверждения, что все работало хорошо.
Если это - способ пойти, то новое () у конструктора должен быть тест для наблюдения, какого конструктора подкласса использовать (если это даже имеет смысл в этом контексте). Вот подклассы:
Как упомянуто выше, это для того, когда объект Foos уже существует.
Это - объект, который будет создан, если, в вышеупомянутом, 'crazyfoo ИМЯ' не будет на самом деле существовать. В этом случае новое () конструктор выше будет проверен на дополнительные параметры, и это будет идти вперед и, на названо использование-> создает (), выходят из оболочки с помощью системы () и создают новый объект... возможно возврат 'Существующего'...
ИЛИ
Поскольку я вывожу это, я понимаю, что это, возможно, лучше иметь сингл:
Класс Foos, который имеет a
-> новый (), который берет просто имя
-> создают (), который берет дополнительные параметры создания
-> удаляют (),-> изменение () и другие параметрические усилители, которые влияют на, которые существуют; это должно будет быть просто проверено динамично.
Таким образом, здесь мы, два основных направления для движения с этим. Мне любопытно, который был бы более интеллектуальным способом пойти.
Вообще, это ошибка (с точки зрения дизайна, а не синтаксиса), что метод new
не возвращает ничего, кроме нового объекта. Если вы хотите иногда возвращать существующий объект, назовите этот метод как-то иначе, например, new_from_cache()
.
Мне также кажется странным, что вы разделяете эту функциональность (создание нового объекта и возврат существующего) не только на отдельные пространства имен, но и на разные объекты. В общем, вам ближе второй подход, но вы все равно можете сделать так, чтобы главный конструктор (new
) обрабатывал различные аргументы:
package Foos;
use strict;
use warnings;
sub new
{
my ($class, %args) = @_;
if ($args{name})
{
# handle the name => value option
}
if ($args{some_other_option})
{
# ...
}
my $this = {
# fill in any fields you need...
};
return bless $this, $class;
}
sub new_from_cache
{
my ($class, %args) = @_;
# check if the object already exists...
# if not, create a new object
return $class->new(%args);
}
Примечание: я не хочу усложнять ситуацию, пока вы еще учитесь, но вы также можете посмотреть на Moose, который позаботится о многих тонкостях конструирования за вас, а также об определении атрибутов и их аксессоров.
Это также шаблон фабрики (плохо в Perl), если конструктор объекта вернет экземпляр, благословленный более чем одним пакетом.
Я бы создал что-то вроде этого. Если существует names
, чем is_created
установлено значение 1, в противном случае установлено значение 0 .. Я бы объединил :: Pending
и : : Существующие
вместе, и если объект не создан, просто поместите его в значение по умолчанию
для _object
, проверка выполняется лениво. Кроме того, Foo-> delete () и Foo-> change () будут относиться к экземпляру в _object
.
package Foo;
use Moose;
has 'name' => ( is => 'ro', isa => 'Str', required => 1 );
has 'is_created' => (
is => 'ro'
, isa => 'Bool'
, init_arg => undef
, default => sub {
stuff_if_exists ? 1 : 0
}
);
has '_object' => (
isa => 'Object'
, is => 'ro'
, lazy => 1
, init_arg => undef
, default => sub {
my $self = shift;
$self->is_created
? Foo->new
: Bar->new
}
, handles => [qw/delete change/]
);
Вообще говоря, для суперкласса плохо знать о своих подклассах, принцип, который распространяется на конструкцию. [1] Если во время выполнения вам нужно решить, какой объект создать (и вы это сделаете), создайте четвертый класс, чтобы иметь именно это задание. Это один из видов «фабрики».
Сказав это в ответ на ваш номинальный вопрос, ваша проблема, как описано, похоже, не требует подклассов. В частности, вы, по-видимому, будете по-разному относиться к различным классам Foos
в зависимости от того, к какому конкретному классу они принадлежат. Все, что вы действительно просите, это унифицированный способ создания экземпляров двух отдельных классов объектов.
Итак, как это предложение[3]: Сделайте Foos::Exists
и Foos::P ending
два отдельных и несвязанных класса и предоставьте (в Foos
) метод, который возвращает соответствующий. Не называйте его new
; Вы не делаете новый Foos
.
Если вы хотите унифицировать интерфейсы, чтобы клиентам не нужно было знать, о каком виде они говорят, то мы можем поговорить о подклассах (или, еще лучше, делегировании лениво созданной и обновленной Foos::Handle
).
[1]: Объяснение того, почему это так, является достаточно большой темой для книги[2], но короткий ответ заключается в том, что она создает цикл зависимостей между подклассом (который зависит от его суперкласса по определению) и суперклассом (который становится зависимым от своего подкласса плохим проектным решением).
[2]: Лакос, Джон. (1996). Крупномасштабный дизайн программного обеспечения C++. Эддисон-Уэсли.
[3]: Не рекомендация, так как я не могу достаточно хорошо разобраться в ваших требованиях, чтобы убедиться, что я не стреляю в рыбу в темном океане.
Интересные ответы! Я перевариваю это, пробуя разные вещи в коде.
У меня есть еще один вариант того же вопроса - тот же вопрос, заметьте, просто другая проблема для того же класса: проблема создания подкласса!
На этот раз:
Этот код представляет собой интерфейс к командной строке, который имеет ряд различных сложных параметров. Я уже говорил вам о / usr / bin / mycrazyfoos
раньше, верно? Что ж, что, если бы я сказал вам, что этот двоичный файл изменяется в зависимости от версии, а иногда полностью меняет его базовые параметры. И этот класс, который мы пишем, должен уметь учитывать все эти вещи. Цель (или, возможно, идея) состоит в следующем: (возможно, это называется FROM класса Foos, который мы обсуждали выше):
Foos :: Commandline, который имеет в качестве подклассов различные версии базовой команды '/ usr / bin / mycrazyfoos' .
Пример:
my $fcommandobj = new Foos::Commandline;
my @raw_output_list = $fcommandobj->getlist();
my $result_dance = $fcommandobj->dance();
где «getlist» и «dance» зависят от версии. Я думал об этом:
package Foos::Commandline;
new (
#Figure out some clever way to decide what version user has
# (automagically)
# And call appropriate subclass? Wait, you all are telling me this is bad OO:
# if v1.0.1 (new Foos::Commandline::v1.0.1.....
# else if v1.2 (new Foos::Commandline::v1.2....
#etc
}
, затем
package Foos::Commandline::v1.0.1;
sub getlist ( eval... system ("/usr/bin/mycrazyfoos", "-getlistbaby"
# etc etc
и (разные файлы .pm, в подкаталоге Foos / Commandline)
package Foos::Commandline::v1.2;
sub getlist ( eval... system ("/usr/bin/mycrazyfoos", "-getlistohyeahrightheh"
#etc
Имеет смысл? Я выразил в коде то, что хотел бы сделать, но это кажется неправильным, особенно в свете того, что обсуждалось в ответах выше. Что ДЕЙСТВИТЕЛЬНО кажется правильным, так это то, что для командной строки должен быть общий интерфейс / суперкласс ... и что разные версии должны иметь возможность переопределять его. Верно? Был бы признателен за пару предложений по этому поводу. Грасиас.