Шаблон проектирования для больших условий в условиях - PullRequest
1 голос
/ 23 сентября 2011

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

Вся система кодирования является беспорядочной TBH, но ее нельзя изменить, и я реорганизовал около 800 строк VB6 до чего-то похожего на следующий код:

string code = foo.GetAccessCodeFromCaller();
if (DatabaseCheck1(code)
{
    parse = ParseCode(code);
    dbValue = GetSomethingFromDB(parse);
    if (OtherCheck1(dbValue)
    {
        // Launch the Pay Taxes project.
    }
    else if (OtherCheck2(dbValue)
    {
        // Launch the Uploaded File project
    }
    else
    {
        // Schedule Something or other project
    }
}
else if (LookForSomethingElseInDB(code)
{
    parse2 = AltParseMethod(code)
    if (Conditional(parse2))
    {
        if (LargeChunkOfCodeConditional(code))
        {
            // Report a something or other project.
        }
        else
        {
            // Talk to Tech Support.
        }
    }
    else
    {
        // Invalid Input
    }
}
else
{
    if (YetAnotherChunkOfCode(code))
    {
        // Order products project
    }
    else
    {
        // Invalid Input.
    }
}

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

До сих пор я пробовал несколько шаблонов (Visitor и Command), но, похоже, ничто не подходит так, как я пытался его реализовать . Любые предложения здесь будут очень благодарны.

EDIT: Чтобы быть более понятным, моя текущая архитектура имеет решение со следующими проектами: Dispatch, PayTaxes, UploadedFiles, ScheduleSomething, ReportSomething, TechSupportRedirect, OrderProducts и т. Д. (Вместе с проектами HardwareAbstraction, SharedInterfaces и DatabaseAccess). Dispatch использует проект HardwareAbstraction, чтобы ответить на телефонный звонок и запросить код вызывающего абонента, а затем направить вызов одному из 10 других проектов, которые выполняют совершенно разные задачи (и затем могут быть перезаписаны параллельно 10 различными разработчиками, без лишних усилий) ,

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

Ответы [ 6 ]

1 голос
/ 23 сентября 2011

Я ничего не знаю о VB6, но как насчет отображения кодов на «делегаты» (не знаю, существует ли эта концепция в VB6). Идея такова: входной код является «ключом» к словарю, возвращающему метод для вызова (или Пустой / Нулевой / Ничего, если такой код не найден).

UPDATE: Если это написано на C #, не могли бы вы просто поместить коды в

Dictionary<string, Action> OpCodes;

Затем сделайте что-то вроде:

if(OpCodes.ContainsKey(code))
  OpCodes[code]();

ОБНОВЛЕНИЕ 2: Кажется, у вас есть «слои» условностей. Я предполагаю, что это будет соответствовать «Словарям словарей». Но если подумать о проблеме: пользователь вводит последовательность выборов, которая должна определенным образом выглядеть, звучит так: определите «делегаты» для каждого поведения системы и сопоставьте с кодами:

Как:

OpCodes["123"] = new Action(TechSupport.StartConversation);
1 голос
/ 23 сентября 2011

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

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

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

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

Для этого типа проблемы есть два общих шаблона:

1) создание подклассов / наследование для достижения полиморфной отправки

2) табличное программирование

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

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

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

Это звучит как работа для Конечного автомата ! Вы даже можете придумать и создать внешний DSL, потому что конечные автоматы очень поддаются этому. На самом деле я только что нашел проект на codeplex , который, кажется, использует телефонную систему в качестве основного примера.

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

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

Что-то вроде

var codeHandler = CodeHandlerDecider.GetCodeHandlerFor(
    foo.GetAccessCodeFromCaller());
codeHandler.HandleCode();

Тогда ваш CodeHandlerDecider будет делать что-то вроде этого:

public static ICodeHandler GetCodeHandlerFor(string code)
{
    if (DatabaseCheck1(code)
    {
        return new FirstCodeHandlerClass(code);            
    }
    else if (LookForSomethingElseInDB(code)
    {
        return new SecondCodeHandlerClass(code);            
    }
    else
    {
        return new ThirdCodeHandlerClass(code);
    }
}

, и тогда пример класса будет

public class FirstCodeHandlerClass: ICodeHandler
{
    public void HandleCode(string code)
    {
        parse = ParseCode(code);
        dbValue = GetSomethingFromDB(parse);
        if (OtherCheck1(dbValue)
        {
            // Launch the Pay Taxes project.
        }
        else if (OtherCheck2(dbValue)
        {
            // Launch the Uploaded File project
        }
        else
        {
            // Schedule Something or other project
        }
    }
}

, а интерфейс будет выглядеть как

public interface ICodeHandler
{
    void HandleCode();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...