8

我有一个名为 Parameters 的对象,它在调用树中从一个方法到另一个方法被扔掉,跨越包边界。它有大约五十个状态变量。每种方法都可能使用一个或两个变量来控制其输出。

我认为这是一个坏主意,因为我无法轻易看到一个方法需要运行什么,甚至如果模块 Y 的参数组合与我当前的模块完全无关,甚至可能发生什么。

有什么好的技术可以减少与这个上帝对象的耦合,或者理想地消除它?

        public void ExporterExcelParFonds(ParametresExecution parametres)
    {
        ApplicationExcel appExcel = null;
        LogTool.Instance.ExceptionSoulevee = false;


        bool inclureReferences = parametres.inclureReferences;
        bool inclureBornes = parametres.inclureBornes;
        DateTime dateDebut = parametres.date;
        DateTime dateFin = parametres.dateFin;

        try
        {
            LogTool.Instance.AfficherMessage(Variables.msg_GenerationRapportPortefeuilleReference);

            bool fichiersPreparesAvecSucces = PreparerFichiers(parametres, Sections.exportExcelParFonds);
            if (!fichiersPreparesAvecSucces)
            {
                parametres.afficherRapportApresGeneration = false;
                LogTool.Instance.ExceptionSoulevee = true;
            }
            else
            {

来电者会这样做:

                PortefeuillesReference pr = new PortefeuillesReference();
            pr.ExporterExcelParFonds(parametres);
4

6 回答 6

9

首先,冒着说明显而易见的风险:传递方法使用的参数,而不是上帝对象。

然而,这可能会导致某些方法需要大量参数,因为它们调用其他方法,而这些方法又调用其他方法等等。这大概就是把所有东西都放在神器里的灵感吧。我将给出一个带有太多参数的方法的简化示例;你必须想象这里的“太多”== 3 :-)

public void PrintFilteredReport(
   Data data, FilterCriteria criteria, ReportFormat format)
{
   var filteredData = Filter(data, criteria);
   PrintReport(filteredData, format);
}

那么问题来了,如何在不求助于神物的情况下减少参数量呢?答案是摆脱过程式编程,充分利用面向对象的设计。对象可以相互使用,而无需知道用于初始化其协作者的参数:

// dataFilter service object only needs to know the criteria
var dataFilter = new DataFilter(criteria);

// report printer service object only needs to know the format
var reportPrinter = new ReportPrinter(format);

// filteredReportPrinter service object is initialized with a
// dataFilter and a reportPrinter service, but it doesn't need
// to know which parameters those are using to do their job
var filteredReportPrinter = new FilteredReportPrinter(dataFilter, reportPrinter);

现在 FilteredReportPrinter.Print 方法可以只用一个参数来实现:

public void Print(data)
{
   var filteredData = this.dataFilter.Filter(data);
   this.reportPrinter.Print(filteredData);
}

顺便说一句,这种关注点分离和依赖注入的好处不仅仅是消除参数。如果你通过接口访问合作者对象,那么你的类

  • 非常灵活:您可以使用您可以想象的任何过滤器/打印机实现来设置 FilteredReportPrinter
  • 非常可测试:您可以通过预设响应传入模拟协作者,并验证它们在单元测试中是否正确使用
于 2009-10-17T02:16:01.893 回答
1

如果你的所有方法都使用同一个Parameters类,那么它可能应该是一个包含相关方法的类的成员变量,那么你可以传递Parameters给这个类的构造函数,将它分配给一个成员变量,你的所有方法都可以使用它必须作为参数传递。

开始重构这个上帝类的一个好方法是将它分成更小的部分。找到相关的属性组并将它们分解为自己的类。

然后,您可以重新访问所依赖的方法,Parameters看看是否可以将其替换为您创建的较小类之一。

如果没有一些代码示例和现实世界的情况,很难给出一个好的解决方案。

于 2009-10-16T20:34:02.873 回答
0

查询每个客户端所需的参数并注入它们?

示例:每个需要“参数”的“对象”都是一个“客户端”。每个“客户端”都公开一个接口,“配置代理”通过该接口向客户端查询其所需参数。然后,配置代理“注入”参数(并且仅是客户端所需的参数)。

于 2009-10-16T20:26:46.710 回答
0

听起来您没有在设计中应用面向对象 (OO) 原则。既然你提到了“对象”这个词,我想你是在某种 OO 范式中工作。我建议您将“调用树”转换为对您正在解决的问题进行建模的对象。“神物”绝对是要避免的。我认为您可能遗漏了一些基本的东西......如果您发布一些代码示例,我可能能够更详细地回答。

于 2009-10-16T20:37:03.283 回答
0

对于指示行为的参数,可以实例化一个显示配置行为的对象。然后客户端类简单地使用实例化的对象——客户端和服务都不必知道参数的值是什么。例如,对于告诉从何处读取数据的参数,让 FlatFileReader、XMLFileReader 和 DatabaseReader 都继承相同的基类(或实现相同的接口)。根据参数的值实例化其中一个,然后读取器类的客户端只需向实例化的读取器对象请求数据,而不知道数据是来自文件还是来自数据库。

首先,您可以将大的 ParametresExecution 类分解为几个类,每个包一个,它们只保存包的参数。

另一个方向可能是在构造时传递 ParametresExecution 对象。您不必在每次函数调用时都传递它。

于 2009-10-17T09:23:05.357 回答
-2

(我假设这是在 Java 或 .NET 环境中)将类转换为单例。添加一个名为“getInstance()”的静态方法或类似于 call 的方法来获取名称-值包(并停止“践踏”它——参见“代码完成”一书的第 10 章)。

现在是困难的部分。据推测,这是在 Web 应用程序或其他一些非批处理/单线程环境中。因此,要在对象不是真正的单例时访问正确的实例,您必须在静态访问器中隐藏选择逻辑。

在java中,你可以设置一个“线程本地”引用,并在每个请求或子任务启动时对其进行初始化。然后,根据该线程本地对访问器进行编码。我不知道 .NET 中是否存在类似的东西,但您总是可以使用 Dictionary (Hash, Map) 来伪造它,它使用当前线程实例作为键。

这是一个开始......(总是会分解 blob 本身,但我构建了一个框架,其中有一个非常相似的半全局值存储)

于 2009-10-16T20:37:35.107 回答