上帝对象 - 减少与“主”对象的耦合

时间:2009-10-16 20:24:17

标签: oop refactoring god-object

我有一个名为Parameters的对象,它跨越包边界,从方法向下向上抛出调用树。它有大约五十个状态变量。每种方法都可以使用一个或两个变量来控制其输出。

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

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

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

6 个答案:

答案 0 :(得分: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
  • 非常可测试:您可以通过预设回复传递模拟协作者并验证它们是否在单元测试中正确使用

答案 1 :(得分:1)

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

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

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

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

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

首先,您可以将您的大型ParametresExecution类分成几个类,每个类一个,只保存包的参数。

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

答案 5 :(得分:-2)

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

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

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

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