避免构造函数有很多参数


10

所以我有一个工厂,可以创建不同类的对象。可能的类都是从抽象祖先派生的。工厂具有配置文件(JSON语法),并根据用户的配置来决定要创建哪个类。

为此,工厂使用boost :: property_tree进行JSON解析。他遍历ptree并决定要创建哪个具体对象。

但是,产品对象具有许多字段(属性)。根据具体的类,对象具有大约5-10个属性,将来可能会更多。

因此,我不确定对象的构造函数应如何。我可以想到两种解决方案:

1)产品的构造函数希望将每个属性作为参数,因此构造函数最终将带有10个以上的参数。这将是丑陋的,并导致较长的,不可读的代码行。但是,优点是工厂可以解析JSON并使用正确的参数调用构造函数。产品类不需要知道由于JSON配置而已创建。不需要知道完全涉及JSON或配置。

2)产品的构造函数只需要一个参数property_tree对象。然后,它可以解析所需的信息。如果配置中的信息丢失或超出范围,则每个产品类别都可以正确响应。工厂不需要知道几种产品需要哪些参数。如果配置错误,工厂也不需要知道如何应对。而且构造函数的接口是统一的,很小的。但是,缺点是,该产品需要从JSON中提取所需的信息,因此,它知道如何构造它。

我倾向于选择解决方案2)。但是,我不确定这是否是好的工厂模式。让产品知道它是用JSON配置创建的,这感觉有点不对劲。另一方面,可以很简单地介绍新产品。

有什么意见吗?



1
我关注了您的链接。棘轮怪胎评分最高的答案中有一个例子。但是,这种“构建器”方法可以解决什么问题?代码行中的DataClass data = builder.createResult();。但是createResults()方法仍然必须将10个参数放入DataClass对象中。但是如何?似乎您只需要再一层抽象,但是DataClass的构造函数却不会变小。
lugge86

看看建造者和原型。
Silviu Burcea 2015年

Silviu Burcea,我做到了。但是,在使用构建器时,构建器如何将参数输入到产品中?某个地方必须是胖接口。构建器只是一层,但是以某种方式必须将参数找到进入产品类的方式。
lugge86

1
如果您的类太大,则在构造函数参数周围移动不会使它不太大
Telastyn

Answers:


10

我不会做选项2,因为那样的话,您就永远用boost属性树解析来卷积对象的构造。如果您对需要这么多参数的类感到满意,则应该对需要那么多参数的构造函数感到满意,例如生命!

如果您主要关注代码的可读性,则可以使用构建器模式,因为缺少命名参数,基本上是c ++ / java的权宜之计。您最终得到如下所示的内容:

MyObject o = MyObject::Builder()
               .setParam1(val1)
               .setParam2(val2)
               .setParam3(val3)
             .build();

因此,现在MyObject将具有一个私有构造函数,该构造函数将在Builder :: build中调用。令人高兴的是,这将是您唯一必须调用带有10个参数的构造函数的地方。boost属性树工厂将使用构建器,随后,如果您想直接构建MyObject或从其他来源构建MyObject,则将遍历该构建器。构建器基本上可以让您在传入每个参数时清楚地命名它们,因此更具可读性。显然,这增加了一些样板,因此与仅调用凌乱的构造函数或将一些现有参数集中到结构中相比,您必须决定是否值得。仅在表上抛出另一个选项。

https://zh.wikipedia.org/wiki/Builder_pattern#C.2B.2B_Example


5

不要使用第二种方法。

这绝对不是解决方案,只会导致在业务逻辑中实例化类,而不是在应用程序中工厂所在的部分。

要么:

  • 尝试将似乎代表相似事物的某些参数归为一组
  • 将当前类拆分为几个较小的类(拥有一个带有10个参数的服务类似乎该类做了太多事情)
  • 如果您的类实际上不是服务,而是值对象,则保持原样

除非要创建的对象实际上是负责保存数据的类,否则应尝试重构代码并将大类拆分为较小的类。


好的,bsiness逻辑使用的是一个返回产品的工厂,因此,业务逻辑看不到JSON / ptree东西。但是我明白你的意思,在构造器中使用Parser代码感觉不对。
lugge86

该类在嵌入式系统的GUI中表示一个小部件,因此,对我来说5个以上的属性似乎还可以:x_coord,y_coord,backgroundcolor,framesize,framecolor,text ...
lugge86

1
@ lugge86即使您使用工厂来解析JSON,从而避免new在业务逻辑中调用或构造对象,但这也不是很好的设计。请参阅MiškoHevery的“ 不要寻找事物”一文,他从测试和阅读的角度更深入地解释了为什么您暗示的工厂方法不好。同样,您的类似乎是一个数据对象,对于这些对象,与常规服务类相比,具有更多的参数通常是可以的。我不会太烦。
安迪

我对工厂的方法感觉很好,但是我会按照您的链接进行考虑。但是,工厂不是本主题中的问题。问题仍然是如何设置产品...
lugge86

“拥有一个带有10个参数的服务类,似乎该类做了太多事情”在机器学习中没有。任何ML算法都有大量的可调参数。我想知道在编写ML时正确的处理方式是什么。
任思远

0

选项2几乎是正确的。

改进的选项2

创建一个“面对”类的人,他的工作是获取该JSON结构对象并挑选出各个位并调用工厂构造函数。它采用工厂制造的产品并将其提供给客户。

  • 工厂绝对不知道这样的JSON是否存在。
  • 客户不必知道工厂需要哪些特定位。

基本上,“前端”是对两个鲍勃的: “我与编辑过的客户打交道,因此工程师不必这样做!我有人际交往能力!” 可怜的汤姆。如果他只说“我使客户与建筑脱钩。那么结果就是一个高度凝聚力的工厂”;他可能会继续工作。

争论太多?

不适合客户端-前端通信。

前端-工厂?如果不是10个参数,那么最好的办法就是推迟解压缩,如果不是原始JSON,则需要一些DTO。这比将JSON传递给工厂更好吗?我说相同的区别。

我会强烈考虑传递单个参数。坚持清洁,有凝聚力的工厂的目标。避免担心@DavidPacker答案。

缓解“参数过多”

  • 工厂或类的构造函数

    • 仅接受特定类/对象构造的参数。
    • 默认参数
    • 可选参数
    • 命名参数
  • 前端参数分组

    • 检查,评估,验证,设置等由上面的构造函数签名指导的参数值。

“工厂绝对不知道这样的JSON东西甚至存在”-那么,工厂的目的是什么?它对产品和消费者都隐藏了产品创建的细节。为什么还要再上一堂课呢?我对工厂用JSON表示满意。一个人可以实现另一个工厂来解析XML,并在将来实现“抽象工厂” ...
lugge86

工厂先生:“您想要什么对象?……那是什么?只需告诉我要构建什么类对象。” 配置文件JSON是数据源,正如Bob叔叔说的“这是实现细节”。它可以从另一个来源和/或以另一种形式。通常,我们希望与特定的数据源详细信息分离。如果源或表格发生更改,工厂将不会更改。给定一个source + parser,并且将工厂作为解耦的模块可以使两者重用。
radarbob
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.