Шаблон Builder для объекта Parameter - PullRequest
0 голосов
/ 23 декабря 2018

Прошу прощения за плохое знание шаблонов проектирования.

Иногда методы имеют много параметров, и введение объекта параметров является правильным способом реорганизовать ваш код в соответствии с refactoring-guruarticle .

Представьте себе ситуацию, когда у нас есть служба, которая обрабатывает какие-то документы.

public class FinancialStatementService : IFinancialStatementService
{
    public Document Create(Options input)
    {
        // creating basic document content and adding optional data below:

        if (input.HasAccountNo)
        {
            // include account number
        }
        if (input.HasPaymentDetails)
        {
            // include payment details
        }
        if (input.HasZeroBalances)
        {
            // include zero balances
        }
        if (input.HasTotal)
        {
            // include total
        }

        // and then return the document
    }
}


public class Options
{
    public DateRange DateRange { get; set; }

    public bool HasAccountNo { get; set; }
    public bool HasPaymentDetails { get; set; }
    public bool HasZeroBalances { get; set; }
    public bool HasTotal { get; set; }
}

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

Но представьте себе случай, когда какая-то организация не хочет некоторых подробностей.

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

public class OptionsCreator
{
    // tax officials want to see all possible details
    public static Options GetTaxOfficeOptions(DateRange dateRange)
    {
        return new Options() { HasAccountNo = true, HasPaymentDetails = true, HasZeroBalances = true, HasTotal = true, DateRange = dateRange };
    }

    // in some other organization they DO NOT NEED zero balances & payment details
    public static Options GetSomeOtherOgranizationOptions(DateRange dateRange)
    {
        return new Options() { HasAccountNo = true, HasTotal = true, DateRange = dateRange };
    }
}

Но я боюсь, что приведенный выше пример является анти-паттерном.

Еще одна вещь, которую я могу подуматьof is Builder Pattern.

Будет ли Builder Pattern наиболее оптимальным решением для объекта параметров ?

Ответы [ 2 ]

0 голосов
/ 24 декабря 2018

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

  1. идентификация роли (организации)
  2. создание зависимого от роли документа
  3. вывод документов

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

Учтите это: в тот самый момент, когда высоздавая или настраивая аргумент параметров для конкретного документа, вы уже знаете, как будет выглядеть документ.Зачем Print(Options) начинать все заново?В тот момент, когда вы знаете варианты, вы можете создать соответствующий документ.Таким образом, вы уже устранили необходимость в типе Options и, что более важно, в проверке состояния уродливого и сложного объекта Options.

Итак, ваш поток начинается с вызова правильного метода, которыйспецифичные для роли.Этот метод создаст документ, который соответствует требованиям этой определенной роли.Так что OptionsCreator становится DocumentCreator.

Как только документ создан, вы передаете его в метод печати.Так что Print(Options) становится Print(Document).Важно, чтобы Print(Document) мог выводить документ, ничего не зная о ролях или деталях документа, а только о том, как и где вывести документ.Теперь, когда вводится новая роль или содержимое документа, Print(Document) не подлежит изменению.Вы только добавили бы новый фабричный метод в DocumentCreator, чтобы создать новый документ, специфичный для новой роли.

Не думаю, что вы можете получить пользу от Строителя прямо здесь.

0 голосов
/ 23 декабря 2018

Я обычно использую что-то вроде этого:

  1. Класс констант с - (в этом примере я использую первый параметр для строки для разбора XML и второй параметр в качестве значения по умолчанию) public static readonly Dictionary<string, Tuple<string, object>> fieldNamesWithOptions = new Dictionary<string, Tuple<string, object>>() { { "number", new Tuple<string, object>("PONumber","") }, { "shipDate", new Tuple<string, object>("ShipDate", new DateTime(1900, 1, 1)) }, { "detailID", new Tuple<string, object>("DetailID", -1) }, }

  2. Обрабатывать такие параметры как (псевдокод, представьте, что третий параметр в Tuple подготавливает функцию):


    for every field F in object O:
        if(fieldNamesWithOptions.ContainsKey(F.name)) 
        {
            result += fieldNamesWithOptions[F].third(O.F);
        }

Я использую псевдокод, потому что вC # это будет выглядеть довольно сложно.

Этот рефакторинг очистит ваш код, разделит логику на маленькие кусочки, которые можно будет понять / протестировать.С другой стороны, у нас есть необычный цикл for every field F in object O:, но будучи отлаженным один раз, он может использоваться каким-то помощником в любых других частях проекта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...