Как бороться с огромными списками параметров? - PullRequest
2 голосов
/ 07 сентября 2011

Так что мой основной класс становился достаточно большим, поэтому я решил инкапсулировать рисунок дисплеев в свой собственный класс.

Затем в обработчике события OnPaint я вызываю displayDrawer.Draw();

Единственная проблема заключается в том, что для рисования чего-либо метод требует довольно много аргументов.

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

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

Очевидный ответ - создать класс или структуру, заполненную такими значениями:

class Offsets
{
    public int horizontal, vertical, displayWidth, displayHeight;

    public Offsets(int horizontal, int vertical, int displayWidth, int displayHeight)
    {
        this.horizontal = horizontal;
        this.vertical = vertical;
        this.displayWidth = displayWidth;
        this.displayHeight = displayHeight;
    }
}

class DrawingFlags
{
    public bool drawCurrentLayer, drawOtherLayers, drawDisplay;

    public DrawingFlags(bool drawCurrentLayer, bool drawOtherLayers, bool drawDisplay)
    {
        this.drawCurrentLayer = drawCurrentLayer;
        this.drawOtherLayers = drawOtherLayers;
        this.drawDisplay = drawDisplay;
    }
}

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

Ответы [ 5 ]

2 голосов
/ 07 сентября 2011

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

Например, ваш класс

class Offsets 
{
    public int horizontal, vertical, displayWidth, displayHeight;

    public Offsets(int horizontal, int vertical, int displayWidth, int displayHeight)
    {
        this.horizontal = horizontal;
        this.vertical = vertical;
        this.displayWidth = displayWidth;
        this.displayHeight = displayHeight;
    } 
}

можно изменить так:

class Offsets
{
    public int horizontal { get; set; }
    public int vertical { get; set; }
    public int displayWidth { get; set; }
    public int displayHeight { get; set; }
}

и может быть заполнено так

var offsets = new Offsets { horizontal = 10, vertical = 20 ... }

Это более читабельно, потому что вы даете имя каждому параметру. Это также intellisenses.

Обратите внимание, что если вы используете C # 4.0, вам не нужно ничего этого делать, поскольку вы можете воспользоваться именованными и дополнительными параметрами :

var result = MyMethod(horizontal: 10, vertical: 20);
1 голос
/ 07 сентября 2011

Но стоит ли это того?

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

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

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

0 голосов
/ 07 сентября 2011

Если вы используете контейнерные классы только один раз и только с целью сокращения списка параметров в одном методе вашего приложения, с 7 параметров (4 смещения и 3 флага) до 2 параметров (два ваших контейнерных класса) тогда я бы сказал, что оно того не стоит.
Это может стоить, если эти классы контейнеров полезны в других областях вашего приложения. В .NET Framework есть много методов с 7 или более параметрами. Это не должно быть проблемой.

0 голосов
/ 07 сентября 2011

Другой идеей может быть передача словаря или чего-то подобного.Я думал о HashMap в Java, но я думаю, что словарь - самая близкая вещь в C #.

0 голосов
/ 07 сентября 2011

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

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

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