【问题标题】:Creating java methods that can be called like this: foo.bar().baz().quux()创建可以像这样调用的 java 方法: foo.bar().baz().quux()
【发布时间】:2010-07-14 20:32:33
【问题描述】:

我不确定它的确切名称,但我想知道如何创建一个可以在一次调用中调用多个方法的类。例如,使用一个android类但没关系,你可以一次调用所有类的方法:


AlertDialog.Builder().setItem().setTitle().setPositiveButton().setCancelable() ...etc

我认为这可行的唯一方法是如果每个方法都返回this,但这似乎会导致问题。我不知道怎么做,但似乎是这样。

另外,这种技术有名字吗?

【问题讨论】:

    标签: java android methods class-design


    【解决方案1】:

    这种技术称为method chaining,它的工作原理与您想象的完全一样。您只需让函数返回 this 而不是 void

    【讨论】:

    • 你是第一个并且用最少的字符回答=]
    【解决方案2】:

    另外,除了构建你的类以始终返回“this”,你还可以使用双括号类实例化技巧,使用普通的 java 类:

    AlertDialog.Builder(){{
      setItem();
      setTitle();
      setPositiveButton();
      setCancelable();
       ...etc
    }}
    

    这是一个很好的参考——http://www.c2.com/cgi/wiki?DoubleBraceInitialization

    【讨论】:

    • 最后是.create()AlertDialog dialog = AlertDialog.Builder() {{ ... }}.create();
    • 我一直使用双括号实例化技巧来测试代码。对于生产代码,我避免使用它......因为每次执行它都会创建一个新类(您正在继承)。这是我希望避免的成本。
    【解决方案3】:

    这就是 建造者模式
    您实际上正在做的是:

    AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
    builder.setIcon(android.R.drawable.icon);
    builder.setTitle(R.string.title);
    builder.setMessage(R.string.message);
    //etc.
    

    【讨论】:

      【解决方案4】:

      它不会引起问题。返回this 是实现此目的的标准做法。

      Java StringBuilder 就是一个例子。 (see source)

      据说这样的类有fluent interface

      【讨论】:

        【解决方案5】:

        这背后的想法是返回对this 的引用。我们来看一个简单的例子:

        class A{
            public A setStuffs(){
                return this;
            }
            public A setOtherStuffs(){
                return this;
            }
        }
        

        那么你可以这样做:

        A a = new A().setStuffs().setOtherStuffs();
        

        您将在使用 Builder 模式的类中看到这一点,例如 AlertDialog.Builder。但是,我通常在我上的每一堂课中都这样做,因为它可以帮助我节省代码行数。

        【讨论】:

          【解决方案6】:

          我一直称这种对象为“建造者”。

          请注意,好的设计往往会在最后调用 .build() 以返回您正在构建的实例。

          正如您所建议的,所有中间方法调用都返回一个构建器对象。如果构建器对象是可变的并且方法调用正在修改某些内部构建器状态,则这可以是“this”。或者,如果构建器对象是不可变的,则每个调用都可以返回一个全新的不可变构建器对象。

          【讨论】:

          • 附注如果您正在设计这样的 API,我建议使构建器对象不可变......从长远来看,当用户开始传递构建器对象并在不同的线程中使用它们时,它可以大大减轻痛苦。通过将支持数据存储在一些持久数据结构中,这很容易做到。
          【解决方案7】:

          这称为方法链接,获得这种效果的最简单方法是从每个方法返回对象的当前实例...

          class MyCoolChainingObject{
          
              public MyCoolChainingObject doSomething(){
                  //TODO: Stuff
                  return this;
              }
          
              public MyCoolChainingObject doSomethingElse(){
                  //TODO: Stuff
                  return this;
              }  
          }
          

          ....

          new MyCoolChainingObject().doSomething().doSomethingElse();
          

          【讨论】:

            【解决方案8】:

            每个描述方法链接的人都举例说明了一种完全合理的方式来实现这一点,但前提是你的函数不需要返回某些东西。如果你想退货怎么办?

            一个(虽然很糟糕)的解决方案是使用 ReturnThis 的布尔参数重载所有方法,该参数调用函数,然后返回 this。但是,我肯定会推荐构建器模式来代替它。

            或者!一个函数,它接受一个按位参数来选择你想要执行的函数! (ZOMG 这是一个糟糕的解决方案!)

            还是!使用 C# 并创建一个方法,该方法接受一个委托参数数组(函数指针),然后遍历数组并调用它们(更糟糕的是!)

            这些是我能想到的唯一选择。如果您不能进行方法链接,请使用构建器,或者只是在自己的行中调用它们。或使用上述三个选项之一(但如果您处于此步骤,请真正质疑您的要求的有效性)。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-03-03
              • 2022-01-17
              • 2013-12-08
              • 2011-11-04
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多