【问题标题】:What's an example of duck typing in Java?什么是 Java 中的鸭子类型的示例?
【发布时间】:2010-11-07 23:08:31
【问题描述】:

我最近刚听说过鸭子打字,我阅读了Wikipedia article 关于它,但我很难将这些示例翻译成 Java,这对我的理解很有帮助。

谁能给出一个用 Java 进行鸭式输入的清晰示例以及我可能如何使用它?

【问题讨论】:

  • 是的,但这里的其他人可能没有读过那篇文章。

标签: java duck-typing


【解决方案1】:

check this library:

interface MyInterface {
    void foo();
    int bar(int x, int y);
    int baz(int x);
}

public class Delegate {
    public int bar() {
        return 42;
    }
}

DuckPrxy duckProxy = new DuckPrxyImpl();
MyInterface prxy = duckProxy.makeProxy(MyInterface.class, new Delegate());
prxy.bar(2, 3); // Will return 42.

使用Dynamic Proxy 的接口duck 输入很简单,您应该匹配方法名称和返回类型。

【讨论】:

  • 应该注意的是,这并不是严格意义上的鸭式输入,而是使用动态代理(这就是它的作用)与 Java 一样接近。
【解决方案2】:

Java 在设计上不适合鸭式打字。您可能选择这样做的方式是反射:

public void doSomething(Object obj) throws Exception {

    obj.getClass().getMethod("getName", new Class<?>[] {}).invoke(obj);
}

但我会提倡使用动态语言(例如 Groovy),这样更有意义:

class Duck {
    quack() { println "I am a Duck" }
}

class Frog {
    quack() { println "I am a Frog" }
}

quackers = [ new Duck(), new Frog() ]
for (q in quackers) {
    q.quack()
}

Reference

【讨论】:

  • ++ 不错的鸭子示例,我喜欢新的对象创建方法。
  • 如果你沿着 Java 反射路线走,就会遇到一个名为“duckapter”的优雅库:code.google.com/p/duckapter
  • 我想知道,为什么在 java 或任何静态类型语言中实现鸭子类型很难或不可能?人们说我们可以使用界面。请解释一下。
【解决方案3】:

Java 没有实现鸭子类型。

【讨论】:

    【解决方案4】:

    Java 中的输入是名义上的——兼容性是基于名称的。如果您需要 Java 中鸭子类型(或结构类型)的示例,请查看此页面:http://whiteoak.sourceforge.net/#Examples,它提供了用 Whiteoak 编写的程序示例:一种也支持结构类型的 Java 兼容语言。

    【讨论】:

      【解决方案5】:

      通常,duck 类型与动态类型语言一起使用。您将在运行时检查是否存在满足您的需求所需的方法或属性,而不管继承层次结构如何。

      除了使用会变得丑陋的反射之外,最接近的方法是使用符合鸭子类型所需条件的最小接口。这个blog post 很好地描述了这个概念。它失去了在 python、ruby 或 javascript 中输入鸭子的许多简单性,但如果您正在寻找高水平的可重用性,它实际上在 Java 中是非常好的实践。

      【讨论】:

        【解决方案6】:

        this blog post。它非常详细地说明了如何使用动态代理在 Java 中实现鸭子类型。

        总结:

        • 创建一个接口,表示您希望通过鸭子类型使用的方法
        • 创建一个使用此接口的动态代理和一个通过反射调用底层对象上的接口方法的实现对象(假设签名匹配)

        【讨论】:

        • 这是一篇好文章 - 你认为你可以总结一下这里给出的解决方案以防万一它发生什么?
        • 添加了一个非常基本的解释。
        • 使用 动态代理 的 Duck 输入甚至可以在更少量的代码中实现 -- 请参阅 this gist。请注意,Proxy 实现的接口的列出顺序很重要:如果不正确,您将收到 java.lang.IllegalArgumentException: object is not an instance of declaring class
        【解决方案7】:

        使用 java 8,您有两种方法:

        nº1:如果您只需要一种方法,请使用 lambdas

        static interface Action { public int act(); }
        
        public int forEachAct(List<Action> actionlist) {
           int total = 0;
           for (Action a : actionList)
               total += a.act();
        }
        
        public void example() {
            List<Action> actionList = new ArrayList<>();
            String example = "example";
            actionList.add(example::length);
            forEachAct(actionList);
        }
        

        nº2:使用匿名类(在性能方面不是很明智,但在某些非关键部分可以做到)

        static interface Action {
            public int act();
            public String describe();
        }
        
        public void example() {
            List<Action> actionList = new ArrayList<>();
            String example = "example";
        
            actionList.add(new Action(){
                public int act() { return example.length(); }
                public String describe() { return "Action: " + example; }
            });
        }
        

        【讨论】:

          【解决方案8】:

          很好的定义:

          对象是多态的,没有共同的基类或接口。

          Reference

          【讨论】:

            【解决方案9】:

            我编写了一个实用程序类来为对象动态创建装饰器。您可以将其用于鸭子打字: https://gist.github.com/stijnvanbael/5965616

            例子:

            interface Quacking {
                void quack();
            }
            
            class Duck {
                public void quack() { System.out.println("Quack!"); }
            }
            
            class Frog {
                public void quack() { System.out.println("Ribbip!"); }
            }
            
            Quacking duck = Extenter.extend(new Duck()).as(Quacking.class);
            Quacking frog = Extenter.extend(new Frog()).as(Quacking.class);
            
            duck.quack();
            frog.quack();
            

            输出:

            Quack!
            Ribbip!
            

            【讨论】:

              【解决方案10】:

              聚会迟到了(和往常一样),但我写了一个快速课程来自己做一些鸭子打字。见here

              它只会转到接口,但对于一个用法示例:

              interface Bird {
                  void fly();
              }
              
              interface Duck extends Bird {
                  void quack();
              }
              
              class PseudoDuck {
                  void fly() {
                      System.out.println("Flying");
                  }
              
                  void quack() {
                      System.out.println("Quacking");
                  }
              }
              
              class Tester {
                  @Test
                  void testDuckTyping() {
                      final Duck duck
                              = DuckTyper.duckType(new PseudoDuck(), Duck.class);
                  }
              }
              

              支持默认接口方法,参数,检查异常类型是否兼容,会检查PseudoDuck类的所有方法(包括私有)。不过,尚未对通用接口进行任何测试。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2016-02-19
                • 2018-07-25
                • 2015-01-24
                • 2015-05-21
                • 1970-01-01
                • 2011-05-18
                • 2018-07-27
                相关资源
                最近更新 更多