Вопрос о структуре классов. Что мне выбрать? - PullRequest
6 голосов
/ 26 сентября 2008

Каковы (если таковые имеются) подразумеваемые предположения или ограничения и различия проектирования, такие как:

А) это:

class SampleClass1
{
    IWorker workerA;
    IWorker workerB;

    void setWorkerA(IWorker w);
    void setWorkerB(IWorker w);
    WorkResult doWork();
}

B) по сравнению с этим:

class SampleClass2
{
    WorkResult doWork(IWorker workerA, IWorker workerB);
}

Я знаю, что это зависит от конкретного проекта, но что, если вышеуказанный класс является частью небольшой структуры? Первый класс может поддерживать состояние и разделять шаги более естественно, но второй класс обеспечивает более естественную связь с внешним абонентом в режиме реального времени, поскольку Worker передается при каждом вызове doWork ().

Существуют ли рекомендуемые способы использования или общие практики, которые определяют выбор между двумя вышеуказанными способами? Спасибо.

Ответы [ 8 ]

6 голосов
/ 26 сентября 2008

SampleClass1

  • Мне может понадобиться поддерживать состояние рабочих между doWork
  • Мне может потребоваться возможность индивидуальной настройки Workers. (doWork с 1 и 2, затем с 2 и 3)
  • Я хочу сохранить рабочих, потому что можно ожидать, что doWork будет запускаться несколько раз на одних и тех же рабочих.
  • Я не служебный класс. Случай со мной важен.

SampleClass2

  • Дайте мне двух рабочих, и я буду работать с ними.
  • Мне все равно, кто они, и я не хочу их поддерживать.
  • Поддерживать любое взаимодействие между работниками - это чужая работа.
  • Я могу быть более утилитарным классом. Может быть, я могу быть просто статичным.
5 голосов
/ 26 сентября 2008

В варианте (A) вы создаете так называемый функциональный объект или функтор, это шаблон проектирования, который хорошо документирован .

Два основных преимущества:

  • Рабочие могут быть установлены в одном месте, а затем в другом месте
  • Объект может сохранять состояние между вызовами

Также, если вы используете инфраструктуру внедрения зависимостей (Spring, Guice и т. Д.), Функтор может автоматически инициализироваться и вставляться везде, где требуется.

Объекты функций широко используются в библиотеках, например стандартная библиотека шаблонов C ++

2 голосов
/ 26 сентября 2008

Другой вариант, вариант случая А, следующий:

class SampleClass3
{
    SampleClass3( IWorker workerA, IWorker workerB );
    WorkResult doWork();
}

Преимущества:

  • Труднее сделать дефектный объект, так как вы обязаны обеспечить всех рабочих, которые необходимы во время строительства (в отличие от случая A).

  • Вы все еще можете переносить состояние внутри SampleClass3 и / или одного из рабочих. (Это невозможно в случае B.)

Недостатки:

  • Прежде чем создавать SampleClass3, необходимо подготовить всех своих работников, чтобы не предоставлять их позже. Конечно, вы также можете предоставить сеттеры, чтобы их можно было изменить позже.
1 голос
/ 26 сентября 2008

A) плохой дизайн, потому что он допускает дефект объекта (один или оба рабочих класса могут быть не установлены).

Б) может быть хорошим. Сделайте это статическим, хотя, если вы не зависите от внутреннего состояния SampleClass2

1 голос
/ 26 сентября 2008

Если от IWorker a и IWorker b зависит несколько методов, я говорю, сделайте образец A.

Если только doWork () использует и IWorker a, и IWorker b, то выполните пример B.

Кроме того, какова реальная цель вашего SampleClass? doWork немного похож на служебный метод mroe, чем все остальное.

0 голосов
/ 26 сентября 2008

Как насчет определения WorkDelegate (или, альтернативно, интерфейса, имеющего единственный метод doWork без аргумента), который просто возвращает WorkResult и позволяет отдельным классам решать, как они его реализуют? Таким образом, вы не ограничиваетесь преждевременными решениями.

0 голосов
/ 26 сентября 2008

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

0 голосов
/ 26 сентября 2008

Другой вариант:

Класс IWorker:

статический WorkResult doWork (Iworker a, Iworker b);

...