首页 > 解决方案 > 参数对象的构建器模式

问题描述

请原谅我对设计模式的了解不足。

有时方法有很多参数,根据refactoring-guru 文章,引入Parameter Object是重构代码的正确方法。

想象一下当我们有一个服务来处理某种文档的情况。

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 };
    }
}

但恐怕上面的例子是反模式。

我能想到的另一件事是建造者模式。

Builder Pattern会是Parameter Object的最佳解决方案吗?

标签: oopdesign-patternsrefactoring

解决方案


我通常这样使用:

  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. 像这样处理你的选项(伪代码,想象元组中的第三个参数正在准备函数):


    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:,但被调试一次,它可以在项目的任何其他部分的一些帮助器中使用。


推荐阅读