Лучше всего приблизьтесь к программированию очень сложных правил бизнеса/математики

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

Как пример:

if (isSoccer)
    val = soccerBaseVal;
else if (isFootball)
    val = footballBaseVal;
.... // 20 different sports

if (isMale)
   val += 1;
else
    val += 5;

switch(dayOfWeek)
{
    case DayOfWeek.Monday:
       val += 12;
    ...
}

и т.д. и т.д. и т.д. с возможно в диапазоне 100-200 различных тестов и изменений формулы.

Это просто походит на кошмар обслуживания. Какие-либо предложения?

Править:

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

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

6
задан Erik Funkenbusch 29 June 2010 в 19:20
поделиться

8 ответов

Обычный способ избежать больших коммутационных структур - поместить информацию в структуры данных. Создайте перечисление SportType и Dictionary , содержащие связанные значения. Вы можете просто написать val + = sportTypeScoreMap [sportType] , и все готово.

Варианты этого шаблона помогут вам во многих подобных ситуациях.

public enum SportType
{
    Soccer, Football, ...
}

public sealed class Foo
{
    private static readonly IDictionary<SportType, Int32> sportTypeScoreMap =
        new Dictionary<SportType, Int32>
        {
            { Soccer, 30 },
            { Football, 20 },
            ...
        }

    private static readonly IDictionary<DayOfWeek, Int32> dayOfWeekScoreMap =
        new Dictionary<DayOfWeek, Int32>
        {
            { DayOfWeek.Monday, 12 },
            { DayOfWeek.Tuesday, 20 },
            ...
        }

    public Int32 GetScore(SportType sportType, DayOfWeek dayOfWeek)
    {
        return Foo.sportTypeScoreMap[sportType]
             + Foo.dayOfWeekScoreMap[dayOfWeek];
    }
}
7
ответ дан 10 December 2019 в 00:32
поделиться

Cribbing от The Pragmatic Programmer, вы можете использовать DSL для инкапсуляции правил и написания механизма процесса. Для представленной проблемы решение может выглядеть так:

MATCH{
    Soccer   soccerBaseVal

    IsMale   5
    !IsMale  1
}

SWITCH{
    Monday   12
    Tuesday  13
}

Затем сопоставьте все в первом столбце MATCH и первом элементе в каждом SWITCH, к которому вы пришли. Вы можете создать любой синтаксис, который вам нравится, а затем просто написать небольшой скрипт, чтобы втиснуть его в код (или использовать Xtext, потому что он выглядит довольно круто).

1
ответ дан 10 December 2019 в 00:32
поделиться

Используйте оператор switch или функцию фильтрации.

Под функцией фильтра я имею в виду что-то вроде:

func filter(var object, var value)
{
    if(object == value)
        object = valueDictionary['value'];
}

Затем примените фильтр с помощью:

filter(theObject, soccer)
filter(theObject, football)

Обратите внимание, что фильтр работает намного лучше с использованием словаря, но это не обязательно.

1
ответ дан 10 December 2019 в 00:32
поделиться

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

EnforceSportRules
ProcessSportDetails
EnforceGenderRules 

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

GenderRules
GenderContext
0
ответ дан 10 December 2019 в 00:32
поделиться

Вот несколько идей:

1 Используйте таблицы поиска:

var val = 0;

SportType sportType = GetSportType();

val += sportvalues[sportType];

Вы можете загрузить таблицу из базы данных.

2 Используйте заводской шаблон:

var val = 0;

val += SportFactory.Create(sportType).CalculateValue();

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

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

1
ответ дан 10 December 2019 в 00:32
поделиться

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

enum Sport
{
    football = 0,
    soccer   = 1,
    //...
}

int sportValues[] = { 
    /* footballValue */,
    /* soccerValue */,
    /* ...Values */
};

int ApplyRules(Sport sport, /* other params */)
{
    int value = startingValue;
    value += sportValues[(int)sport];
    value += /* other rules in same fashion */;
}
0
ответ дан 10 December 2019 в 00:32
поделиться

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

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

if (isSoccer)              val = soccerBaseVal;  
if (isMale)                val += 1; 
else                       val += 5; 

switch(dayOfWeek){ 
    case DayOfWeek.Monday: val += 12; 
    ... 
}  

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

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

Рассмотрите возможность реализации шаблона стратегии , который использует наследование / полиморфизм, чтобы сделать управление отдельными функциями разумным. Разделив каждую функцию на отдельный выделенный класс, вы можете избавиться от кошмара длинных блоков case или if операторов.

Не уверен, поддерживает ли это C # еще (или когда-либо будет), но VB.NET интегрирует директивы XML Comment CompletionList в intellisense, что - в сочетании с шаблоном стратегии - может дать вам легкость использование Enum с неограниченной расширяемостью OO.

0
ответ дан 10 December 2019 в 00:32
поделиться
Другие вопросы по тегам:

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