Строительство объекта / метод перегрузки - PullRequest
1 голос
/ 20 августа 2011

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

# Every 2 days.
$event = Event::Recurrence->new( recurs => 'daily', interval => 2 );

# 1st and 2nd day of every 3rd week.
$event = Event::Recurrence->new( recurs => 'weekly',  days => [1, 2], interval => 3 );

# 1st and 2nd day of every 4th month.
$event = Event::Recurrence->new( recurs => 'monthly', days => [1, 2], interval => 4 );

# 1st and 2nd day of the 2nd and 3rd week of every month.
$event = Event::Recurrence->new( recurs => 'monthly', days => [1, 2], weeks => [2, 3], interval => 1 );

# 1st and 2nd day of the 2nd and 3rd week of every year.
$event = Event::Recurrence->new( recurs => 'yearly',  days => [1, 2], weeks => [2, 3], interval => 1 );

# 1st and 2nd day of the 2nd and 3rd week of the 3rd and 4th months of every 5th year.
$event = Event::Recurrence->new( recurs => 'yearly',  days => [1, 2], weeks => [2, 3], months => [3, 4], interval => 5 );

# Do something with the event object.
$set = $event->get_set();

get_set() будет работать по-разному в зависимости от параметров построения.

Я не ищу способы реализации обработки даты - я использую повторяющиеся события, чтобы проиллюстрировать тип проблемы.Вместо этого я ищу более общую информацию о хороших способах обработки различных возможных комбинаций параметров для соответствующих методов.Я использую Moose, поэтому шаблоны Moose / OO приветствуются.

Приведенные выше примеры можно широко разбить на различные типы событий: ежедневные, еженедельные, ежемесячные и ежегодные.Каждый из них будет обрабатывать оставшиеся параметры по-разному, но конечный результат будет представлять собой объект одного типа - набор повторяющихся событий, над которыми могут выполняться определенные операции (получение даты начала и окончания, определение пересечений и т. Д.).

get_set() может поэтому реализовать диспетчерскую таблицу для обработки всех возможных комбинаций параметров, вызывая отдельный метод для каждого - но это выглядит грязно.

Я мог бы создать CodeRef атрибут вместе с отдельными классами для различных типов повторения (Event::Recurrence::Daily, Event::Recurrence::Weekly и т. д.) и присвоение соответствующего класса атрибуту во время построения, аналогично принятому ответу на этот вопрос - хотя я не уверен, как бы это реализовать.

1 Ответ

0 голосов
/ 21 августа 2011

Вы, вероятно, должны иметь отдельные подклассы для каждого вида повторяющихся событий, например, класс DailyRecurringEvent, класс WeeklyRecurringEvent, класс MonthlyRecurringEvent и т. д.

(Примечание: ежедневные и еженедельные повторяющиеся события могут быть реализованы в виде экземпляров «каждое повторяющееся n-дневное событие», т.е. n = 1 для ежедневных событий и n = 7 для еженедельных событий.)

Вместо вызова ->get_set для ваших объектов событий, я бы рассматривал сами объекты как "наборы событий". Теперь возникает вопрос: какие операции вы хотите поддерживать на своих наборах и какие другие вспомогательные классы могут вам понадобиться.

Пример. Предположим, вы хотите поддержать операцию, которая получает следующее происходящее событие из набора событий после определенного дня. Назовите эту операцию «next_event_after». Выполнить это для каждого из вышеперечисленных классов (то есть ежедневно, еженедельно, ежемесячно, ежегодно) довольно просто.

Теперь вы сказали, что хотите иметь возможность пересечения наборов событий. Как насчет нового класса с именем «EventSetIntersection», который представляет пересечение коллекции наборов событий. Операция «next_event_after» для пересечения может быть реализована примерно так:

package EventSetIntersection;

use Moose;
has event_sets => (
  is => 'rw',
  isa => 'Array[EventSets]',
);
sub next_event_after {
  my ($self, $date) = @_;
  return min { $_->next_event_after($date) } @{ $self->event_sets };
}

Напомним, что ваши исходные классы были EventSets, поэтому вы можете создать пересечение напрямую:

my $weekely_event = WeeklyEvent->new(...);
my $yearly_event = YearlyEvent->new(...);
my $intersection = EventSetIntersection->new( event_sets => [ $weekly, $yearly ]);
...