Определенные функции по сравнению со многими Аргументами по сравнению с контекстно-зависимым

Пример

Предположим, что мы имеем текст для записи и могли быть преобразованы в "верхний регистр или нижний регистр", и можем быть распечатаны "в левом, центральном или правильном".

Реализация конкретного случая (слишком много функций)

writeInUpperCaseAndCentered(char *str){//..}
writeInLowerCaseAndCentered(char *str){//..}
writeInUpperCaseAndLeft(char *str){//..}
and so on...

по сравнению с

Многие функция Аргумента (плохая удобочитаемость и даже трудно кодировать без хорошего автозавершения IDE)

write( char *str , int toUpper, int centered ){//..}

по сравнению с

Контекстно-зависимый (трудно к повторному использованию, трудно для кодирования, использование ужасного globals, и иногда даже невозможный "обнаружить" контекст)

writeComplex (char *str)
{    
    // analize str and perhaps some global variables and 
    // (under who knows what rules) put it center/left/right and upper/lowercase
}

И возможно существуют опции других.. (и приветствуются),

Вопрос:

Есть ли хорошо работает практика или совет опыта / академический совет для этого (текущего) trilemma?

Править:

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

7
задан Hernán Eche 17 August 2010 в 15:25
поделиться

6 ответов

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

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

Остается третий вариант. Вы действительно можете получить некоторые преимущества других альтернатив с помощью битовых флагов. Например,

#define WRITE_FORMAT_LEFT   1
#define WRITE_FORMAT_RIGHT  2
#define WRITE_FORMAT_CENTER 4
#define WRITE_FORMAT_BOLD   8
#define WRITE_FORMAT_ITALIC 16
....
write(char *string, unsigned int format)
{
  if (format & WRITE_FORMAT_LEFT)
  {
     // write left
  }

  ...
}

РЕДАКТИРОВАТЬ: Чтобы ответить Грегу С.

Я думаю, что самое большое улучшение состоит в том, что если я на этом этапе решу добавить поддержку подчеркнутого текста I, потребуется два шага

  1. Добавить #define WRITE_FORMAT_UNDERLINE 32 в заголовок
  2. Добавить поддержку подчеркивания в write () .

Здесь он может вызывать write (..., ... | WRITE_FORMAT_UNLDERINE) где угодно. Более того, мне не нужно изменять ранее существовавшие вызовы для записи, что мне пришлось бы сделать, если бы я добавил параметр в его подпись.

Еще одним потенциальным преимуществом является то, что он позволяет вам делать что-то вроде следующего:

#define WRITE_ALERT_FORMAT  (WRITE_FORMAT_CENTER | \
                             WRITE_FORMAT_BOLD |   \
                             WRITE_FORMAT_ITALIC)
7
ответ дан 6 December 2019 в 19:32
поделиться

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

0
ответ дан 6 December 2019 в 19:32
поделиться

Как вы уже упоминали, одна поразительная особенность - удобочитаемость: writeInUpperCaseAndCentered ("Foobar!") намного легче понять, чем write ("Foobar!", true, true) , хотя вы можете устранить эту проблему, используя перечисления. С другой стороны, наличие аргументов позволяет избежать таких неудобных конструкций, как:

if(foo)
  writeInUpperCaseAndCentered("Foobar!");
else if(bar)
  writeInLowerCaseAndCentered("Foobar!");
else
 ...

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

0
ответ дан 6 December 2019 в 19:32
поделиться

Я предпочитаю аргумент.

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

Вместо использования аргумента для каждого отдельного случая (toUpper, по центру и т. Д.) Используйте структуру. Если вам нужно добавить больше случаев, вам нужно только изменить структуру:

typedef struct {
    int toUpper;
    int centered;
    // etc...
} cases;
write( char *str , cases c ){//..}
3
ответ дан 6 December 2019 в 19:32
поделиться

Я бы выбрал комбинацию методов 1 и 2.

Напишите метод (A), который имеет все аргументы, которые вам нужны/можете придумать прямо сейчас, и "голую" версию (B) без дополнительных аргументов. Эта версия может вызывать первый метод со значениями по умолчанию. Если ваш язык поддерживает это, добавьте аргументы по умолчанию. Я также рекомендую использовать осмысленные имена для аргументов и, по возможности, перечисления, а не магические числа или серию флагов true/false. Это значительно облегчит чтение вашего кода и позволит узнать, какие значения на самом деле передаются, без необходимости искать определение метода.

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

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

2
ответ дан 6 December 2019 в 19:32
поделиться

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

Одним из основных преимуществ этого является то, что я могу создавать объекты, которые определяют логические форматы вместо физических форматов. Это позволяет, например, сделать что-то вроде:

Format title = {upper_case, centered, bold};
Format body = {lower_case, left, normal};

write(title, "This is the title");
write(body, "This is some plain text");

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

1
ответ дан 6 December 2019 в 19:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: