Вызов метода в классе или передача в качестве параметра другому классу? C # - PullRequest
3 голосов
/ 28 ноября 2009

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

Я хочу иметь возможность распечатать эти данные, поэтому мне интересно, есть ли более предпочтительный дизайн для этого. На данный момент у меня есть две идеи - вызвать метод Print () для самого Job или передать экземпляр Job в какой-то класс контроллера печати, например:

job.Print();

или

PrintWidget pw = new PrintWidget(job);
pw.Print();

В настоящее время я не могу предусмотреть печать чего-либо, кроме данных из этого класса Job. Однако кто знает, что нас ждет в будущем. Имея это в виду, было бы лучше иметь отдельные методы Print () для любых классов, которые я хотел бы напечатать, или один класс контроллера печати, который может обрабатывать различные типы объектов для печати?

Как бы вы пошли на разработку этого? Заранее спасибо за любые ответы.

Ответы [ 4 ]

7 голосов
/ 28 ноября 2009

Ваша проблема полностью соответствует принципу единственной ответственности (SRP) , одному из принципов SOLID .

Принцип, по сути, гласит, что правильно спроектированный компонент должен отвечать только за одну задачу. Другой способ взглянуть на это состоит в том, что компонент должен иметь только одну причину для изменения. Это гарантирует, что когда вам нужно что-то изменить, вы знаете, что все функции будут в одном месте и не будут смешаны с другими функциями .

В вашем случае Job предположительно имеет какую-то функциональность, отличную от печати, возможно, некоторые обязанности представлять "работу" в вашей доменной модели. Если это так, то вы не хотите добавлять функции печати здесь. Вместо этого создайте свой виджет печати и разместите там всю логику для печати. ​​

Если ваша печать должна измениться, вам не нужно прикасаться к объекту Job, потому что его обязанности не изменились. Аналогичным образом, если меняется концепция «задания», изменяется только класс Job, и печать остается неизменной (если у вас нет сейчас чего-либо дополнительного для печати).

Однако ...

Если цель Job класса только *1022* состоит в том, чтобы представить некоторую информацию для печати, то наиболее определенно должен содержать метод PrintTo(Printer), где Printer будет нести ответственность за разговор с физическим принтером. В этом случае ответственность перешла на Job, которая связана только с печатью, и целесообразно, чтобы она контролировала способ печати. ​​

SRP может быть трудным для понимания в ваших проектах, но есть простой способ убедиться:

Если вы можете подвести итог функциональности ваш класс без использования слова «а», класс имеет единственный ответственность.

Итак, Job отвечает либо за «представление задания», либо за «печать информации о задании», но не за оба.

3 голосов
/ 28 ноября 2009

Является ли знание печати ключевой частью вашего Job класса? Если нет, то, вероятно, не должно быть в этом классе (разделение интересов и т. Д.). Это применимо вдвойне, если печать может отличаться в разных контекстах. Я, вероятно, сделал бы что-то более похожее на:

PrintWidget pw = new JobPrintWidget(); // perhaps via abstract-factory
pw.Print(job);

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

Что касается меня, то работа больше похожа на ввод, но если виджет должен печатать только 1 работу, пусть будет так.

Другая возможность (в C # 3) - это метод расширения:

static class PrintUtil {
    public static void Print(this Job job) {...}
}

, который позволяет использовать job.Print(), но без помещения кода в Job.

2 голосов
/ 28 ноября 2009

Один из вариантов - использовать Методы расширения , который был представлен в C # 3.0. Методы расширения позволяют расширять класс, не используя его, что обеспечивает большую гибкость. Используя методы расширения, вы можете добавить метод Print в класс Job и любой другой класс, не изменяя исходный класс. E.g.:

static class PrintExtensions
{
    public static void Print (this Job job)
    {
        // TODO: print Job
    }

    public static void Print (this SomeOtherClass c)
    {
        // TODO: print SomeOtherClass
    }
}

Как только вы определили метод расширения, вы используете его так, как если бы он был определен в самом классе, например:

Job job = GetJob();
job.Print(); // call PrintExtensions.Print(this Job job)
0 голосов
/ 28 ноября 2009

Лично я бы поместил метод Print в класс Job. Если вы создадите отдельный класс PrintWidget, он должен знать все о классе Job. В любом случае, если выяснится, что вам нужен или нужен PrintWidget в будущем, вы всегда можете создать его и рефакторизовать метод Print класса Job.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...