Как мне справиться с комбинациями поведения? - PullRequest
2 голосов
/ 30 июня 2009

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

Вещественные числа могут иметь различные комбинации форматов, например: 1. с / без знака на передней панели 2. с / без десятичной точки (если нет десятичной точки, то, возможно, число десятичных знаков может быть согласовано заранее) 3. основание 10 или основание 16

Нам нужно учесть каждую комбинацию, поэтому есть 2x2x2 = 8 комбинаций. Вы можете видеть, что сложность увеличивается экспоненциально с каждым новым наложенным условием.

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

В процедурном программировании вы используете 3 флага (то есть has_sign, has_decimal_point и number_base), чтобы идентифицировать свойство действительного числа, которое вы проверяете. У вас есть одна функция для проверки. Там вы будете использовать флаги для управления его поведением.


// This is part of the validation function</p>

<p>if (has_sign)
   check_sign();</p>

<p>for (int i = 0; i < len; i++)
{
    if (has_decimal_point)
        // Check if number[i] is '.' and do something if it is. If not, continue</p>

<pre><code>if (number_base = BASE10)
    // number[i] must be between 0-9
else if (number_base = BASE16)
    // number[i] must be between 0-9, A-F

}

Опять же, сложность вскоре выйдет из-под контроля, поскольку функция загромождена операторами if и флагами.

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

Помогло бы что-нибудь вроде схемы моста?

Ответы [ 5 ]

4 голосов
/ 30 июня 2009

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

Нет, нет, нет, нет. Самое большее, у вас будет тип для представления Числовой ввод (в случае, если String не делает этого); еще один для Действительное число (на большинстве языков вы бы выбрали встроенный тип, но в любом случае); и Parser класс, который обладает знаниями для того, чтобы взять числовой ввод и преобразовать его в вещественное число.

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

Если (представив, что вы пишете свой собственный анализатор), у вас может быть знак или нет, десятичная точка или нет, и шестнадцатеричный или нет, у вас есть три независимых источника сложности , и все будет в порядке где-то найти три фрагмента кода, каждый из которых решает одну из этих проблем; но было бы неправильно найти где-нибудь 2 ^ 3 = 8 различных фрагментов кода, которые явно обрабатывают различные комбинации.

Представьте себе, что добавьте новый выбор: внезапно вы вспомните, что числа могут иметь «е» (например, 2.34e10), и хотите иметь возможность поддержать это. При ортогональной стратегии у вас будет еще один независимый источник сложности , четвертый. С вашей стратегией, 8 случаев внезапно станут 16! Очевидно, нет-нет.

2 голосов
/ 30 июня 2009

Вы запрашиваете парсер, используйте один:

Также: http://en.wikipedia.org/wiki/Parser_generator

Теперь, как мне справиться со сложностью для такого рода проблем? Хорошо, если я могу, я переформулирую.

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

Шаблон проектирования и ООП полезны, но определенно не лучшее решение для каждой проблемы.

2 голосов
/ 30 июня 2009

Я не знаю, почему вы думаете, что ОО-решение будет включать класс для каждого числового шаблона. Мое решение OO было бы использовать класс регулярного выражения. И если бы я был процедурным, я бы, вероятно, использовал стандартную библиотечную функцию strtod ().

0 голосов
/ 30 июня 2009

Вы не убиваете муху молотком.

Я действительно чувствую, что использование объектно-ориентированного решения для вашей проблемы - КРАЙНЕЕ излишество. То, что вы можете разрабатывать объектно-ориентированное решение, вовсе не означает, что вам нужно навязывать такое решение каждой имеющейся у вас проблеме.

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

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

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

0 голосов
/ 30 июня 2009

Извините, но так как я использую vb, то, что я делаю, является базовой функцией, тогда я объединяю функцию оценщика так плохо, поддельный код, как я это сделал

function getrealnumber(number as int){ return  getrealnumber(number.tostring) }
function getrealnumber(number as float){ return  getrealnumber(number.tostring) }
function getrealnumber(number as double){ return  getrealnumber(number.tostring) }
function getrealnumber(number as string){
if ishex(){ return evaluation()}
   if issigned(){ return evaluation()}
   if isdecimal(){ return evaluation()}
 }

и так далее до вас, чтобы выяснить, как сделать двоичные и восьмеричные

...