【问题标题】:Best way to pass arguments in constructor在构造函数中传递参数的最佳方法
【发布时间】:2013-05-28 06:52:56
【问题描述】:

我有一个在表格布局中创建行的类。行的创建取决于数据和元数据。由于元数据对于每一行都是相同的,例如显示/隐藏可见性属性等,所以我将元数据属性创建为静态并使用 initWidgetRowWidget 初始化一次。

举例:

class RowWidget extends FlexTable{

  public static void initWidget(Form form,
    HashMap<Long, ContractorPermissionEnum> formModePermissionMap,
    GridMode gridMode,
    boolean isApplied,
    boolean isChildExist,
    boolean isChildAttachment)
    { 
      // ...
    }
}

然后我为每个记录数据调用下面的构造函数。

public RowWidget(DataRawType dataRawType, Data data, Data parentData) {
 // ...
}

我认为这不是正确的方法。因为当任何人看到这个类然后理解它会创建一行时,作为模式。我最初不想打电话给initWidget。我想在构造函数中传递每个必需的参数,就像

public RowWidget(DataRawType dataRawType,
  Data data,
  Data parentData,
  Form form,
  HashMap<Long, ContractorPermissionEnum> formModePermissionMap,
  GridMode gridMode,
  boolean isApplied,
  boolean isChildExist,
  boolean isChildAttachment) {
  // ...
}

但是由于这个原因,构造函数没有参数。而且我认为在构造函数中有 5+ 参数也是不好的模式。

有人推荐我吗:

  • 如何构造具有相同属性的类 实例?

注意:我知道这只能通过静态实现,但不想使用静态。

  • 什么是构建类的最佳方法,有一些默认修复 所有实例的属性?

注意:我不想创建另一个类来实现它。或任何 getter/setter 方法。

提前致谢。

【问题讨论】:

  • 如果您将布尔参数转换为MapSet,就像您对表单权限所做的那样,您可以稍微减少参数列表的长度
  • 是的,我可以。让我们任何人都不要有另一种方法。我会去的。
  • 好吧,如果你真的不想要任何新类,想要摆脱静态和长参数列表,这个 DIRTY 建议怎么样:使用Map&lt;String, Object&gt;要保存您的参数,请填写一次并将该映射传递给RowWidget 构造函数,然后在构造时获取+转换它们以供使用。这比拥有长参数列表更糟糕,因为最后一个参数列表更明确地说明了类需要哪些参数并且更具可读性/可维护性。您还应该重新考虑您的设计。是什么阻碍了您引入新课程?
  • @A4L 呵呵,这正是我在阅读 no-new-class-note 时的第一个想法,但我不敢提出建议;)
  • @MarcoForberg 哈哈...这就是为什么它只作为评论出现;-)

标签: java design-patterns


【解决方案1】:

我会建议构建器模式。您将需要一个额外的类来创建 RowWidget 对象。所以调用看起来像这样:

RowWidget widget = new RowWidget.Builder().withData(data).withParentData(parentData).withDataRawType(dataRawType).build();

这是对模式的简洁解释:https://stackoverflow.com/a/1953567/991164

【讨论】:

  • 但是这里有丢失东西的机会
  • 如果您需要确保没有任何参数丢失,只需在 build() 方法中执行检查,如果是则抛出异常。
【解决方案2】:

为什么不创建一个方法,该方法将接受您要更改的属性的 newValues 并返回一个新的类实例以及从您调用此方法的实例复制的所有其他属性。

【讨论】:

    【解决方案3】:

    您可以从RowWidget-class 中分离/提取参数,例如RowWidgetConfig-class。

    class RowWidgetConfig {
        // put here all your parameters that you need to initialize only once
        // init using setters
    }
    

    现在创建该类的一次实例,并将其与其他参数一起传递给RowWidget 构造函数。

    另一种选择是使用factory 来创建RowWidget 实例。工厂还将包含行实例所需的所有参数以及工厂方法createNewRowWidget,它会根据工厂中包含的参数创建实例。

    class RowWidgetFactory {
        // put here all your parameters that you need to initialize only once
        // init using setters
    
        public RowWidget createNewRowWidget() {
            // create
            return ...
        }
    }
    

    【讨论】:

    • OP 说他不想再上课了。 “注意:我不想创建另一个类来实现它。”
    • @MarcoForberg 哎呀,我错过了那个细节:/
    • 但我不得不承认,配置类是我首先想到的;9
    • @MarcoForberg 我真的很好奇如何做到这一点!我将删除此答案,因为它对 OP 没有帮助。
    • 我也是!我认为配置类会很好,尽管他不想要一个新类。
    【解决方案4】:

    如何在另一个实例中构造具有相同属性的类?

    要实现这一点,您可以拥有一个包含您想要的所有属性的超类。所以任何扩展这个超类的类都将具有这些属性。这样就不需要使用static关键字了。

    为所有实例设置一些默认修复属性的类的最佳构造方法是什么?

    对于这个,您可以拥有一个具有一些常量属性的接口。这样,任何实现此接口的类都将具有固定的属性。

    【讨论】:

    • 我知道超级班,但请阅读我的问题。我不需要它。当没有控件具有相同的属性时,AFAIK 超类需要。在这里我只有一个控件。并且为了初始化超类,我需要构造函数。正确的?所以我也必须通过一些方式在那里..对吗?怎么样?
    • @Bhumika:由于多个控件具有相同的属性,因此您可以简单地在超类中定义它们,因此您只需要默认的无参数构造函数。
    【解决方案5】:

    静态的 initWidget() 似乎不适合我。尽管现在您可能只有一组RowWidgets 共享一些属性,但拥有2 组RowWidgets 也是合理的,每组都有自己的“共享”属性。如果您重构代码以进行更合理的设计,事情将会更加流畅,并且您在构建更合理的 API 方面有更多选择

    现在假设我引入了类似 RowGroup 的东西(代表你提到的“共享”的东西)

    (老实说,我不太明白你的设计的含义,我只是根据你的代码来编造它);

    public class RowGroup {
        public RowGroup(Form form,
                        HashMap<Long, ContractorPermissionEnum> formModePermissionMap,
                        GridMode gridMode,
                        boolean isApplied,
                        boolean isChildExist,
                        boolean isChildAttachment) { .... }
    
        public void addRow(DataRawType dataRawType, Data data, Data parentData) {...}
    }
    

    当人们使用时,它看起来像:

    RowGroup rowGroup = new RowGroup(form, permissionMap, gridMode, isApplied, isChildExist, isChildAttach);
    rowGroup.addRow(DataRawType.A, dataA, parentA);
    rowGroup.addRow(DataRawType.B, dataB, parentB);
    

    您甚至可以提供类似构建器的语法或许多其他选择。

    RowGroup rowGroup 
            = new RowGroup(.....)
                  .addRow(DataRawType.A, dataA, parentA)
                  .addRow(DataRawType.B, dataB, parentB);
    

    更重要的是,现在设计对我来说更有意义。

    【讨论】:

      【解决方案6】:

      如果您不想创建另一个类,我会建议 A4L 的建议。 在不创建另一个类的情况下,我将创建接受所有参数的构造函数和使用当前实例作为模板的工厂方法,并将其自己的参数传递给构造函数参数。

      示例(省略明显部分)

      class A{
        public A(int p1, int p2){...}
        public A create(int p2) {
          return new A(this.p1,p2);
      }
      

      【讨论】:

        猜你喜欢
        • 2018-01-07
        • 1970-01-01
        • 1970-01-01
        • 2017-03-28
        • 2011-09-04
        • 2014-09-10
        • 1970-01-01
        • 2021-02-25
        相关资源
        最近更新 更多