Можно ли передавать набор параметров в функцию используя объект Options с т.з. ООП?

Рейтинг: 1Ответов: 5Опубликовано: 14.04.2015

У нас есть объект, выполняющий некую полезную работу. Ему необходимо передать набор параметров, опций. Предположим, что кол-во параметров может доходить до 10. Что более правильно и красиво - передавать параметры обычным образом или же создать некий класс опций, для хранения этих параметров и передавать его?

Наприме, так:

internal class Options
{
        public bool Debug { get; set; }
        public bool Verbose { get; set; }
        public bool StopOnErrors { get; set; }
        public bool SkipExisting { get; set; }
        public bool CheckOnly { get; set; }
        public bool Pause { get; set; }

        public char FieldDelimiter { get; set; }
        public char ListDelimiter { get; set; }

        public Options()
        {
            Debug = false;
            Verbose = true;
            CheckOnly = false;
            StopOnErrors = true;
            SkipExisting = false;
            Pause = false;
            FieldDelimiter = ',';
            ListDelimiter = ';';
        }
}

Ответы

▲ 2Принят

Нужно! Но только если параметры логически связаны.

Методы с количеством параметров больше 3-5 становятся трудноподдерживаемыми. И инкапсуляция как всегда приходит нам на помощь: прячем несколько параметров внутри класса и передаем экземпляр этого класса как параметр метода. Мартин Фаулер в своей классической книге по рефакторингу выделяет это в отдельный случай: Introduce Parameter Object.

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

▲ 1

Да, по факту это просто повторение структур из никзоуровневых языков (с точки зрения используемого функционала, конечно), и называется такая штука data transfer object / business object. Она часто критикуется за фактическое отсутствие поведения, но, по-моему, она выполняет именно ту роль, для которой создана - строгий перенос данных (в PHP, скажем, туда-сюда могут гоняться массива из чего угодно, подобный подходя "закрепляет" названия полей и форсирует консистентность кода) и не нужно от нее требовать чего-то еще. Единственное, что стоит сказать - насколько знаю, в C# есть структуры из коробки, и, наверное, лучше использовать их, если никакого поведения не предусматривается (иногда в DTO сразу встраивается минимальное форматирование или подтягивание других DTO).

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

▲ 1

Лично я голосую за класс.
Преимуществ масса:

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

    someMethod(true, false, ... );
    

    использовать

    someMethod(new Options { Debug = true, Verbose = false, ... });
    
▲ 1

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

▲ 1

С точки зрения ООП такой класс не является классом. Но это не означает, что его нельзя использовать.

PS есть еще одна возможность в C# - именованные параметры. Они выглядят проще, чем Options - но их сложнее передавать по цепочке в другие методы. Сравните:

someMethod(new Options { Debug = true, Verbose = false });

и

someMethod(debug: true, verbose: false);