代码之家  ›  专栏  ›  技术社区  ›  Ingo

在事实之后实现接口

  •  5
  • Ingo  · 技术社区  · 17 年前

    我认为,以下不能用Java来完成。但是我很乐意学习如何实现类似的东西。

    假设我们有一个C类,它已经在编译代码中使用了。(我们既不能更改代码,也不能更改C的原始定义)。

    假设还有一些有趣的代码可以重用,如果只有C可以实现接口I的话。事实上,派生D或多或少是微不足道的,它只是C+接口方法的实现。

    然而,一旦我有了一个C,似乎就没有办法说:我想让你成为一个D,也就是说,实现I的C。

    (旁注:我认为,如果d是c,而c的运行时类型是c,那么应该允许使用cast(d)c,而c的唯一区别是添加了方法。这应该是安全的,不是吗?)

    如何才能解决这场灾难?

    (我知道工厂的设计模式,但这似乎不是解决方案。因为,一旦我们在所有以前是C的地方创建了D,其他人就会发现另一个接口J很有用,并且派生出E扩展了C实现J。但是E和D是不兼容的,因为它们都向C添加了一组不同的方法。因此,虽然我们总是可以在预期是C的地方传递E,但是我们不能在预期是D的地方传递E。相反,现在,我们需要一个新的类f扩展c实现i,j。)

    6 回复  |  直到 9 年前
        1
  •  7
  •   Lesque    9 年前

    如果您需要兼容的只是接口,那么就没问题了。 dynamic proxy classes 它基本上是如何在Java中运行时实现接口的。

    如果您需要与类具有类似的运行时兼容性,我建议您查看cglib或javaassist开放源码库。

        2
  •  10
  •   Alnitak    17 年前

    您不能使用委托类,即包装“class c”实例并实现“interface i”的新类吗?

    public class D implements I {
    
        private C c;
    
        public D (C _c) {
            this.c = _c;
        }
    
        public void method_from_class_C() {
            c.method_from_class_C();
        }
        // repeat ad-nauseum for all of class C's public methods
        ...
    
        public void method_from_interface_I() {
            // does stuff
        }
        // and do the same for all of interface I's methods too
    }
    

    然后,如果需要调用一个函数,该函数通常采用类型的参数 I 只要这样做:

    result = some_function(new D(c));
    
        3
  •  3
  •   Joachim Sauer    17 年前

    如果你能 ClassLoader 这是你的课 C 然后,您可以尝试使用字节码插入来执行一些类加载时间恶作剧,以使类实现接口。

    当然,在构建期间也可以这样做。这样做可能更容易(因为您不需要访问类加载器)。

        4
  •  2
  •   Dave Costa    17 年前

    (旁注:我认为演员(D)C, 如果C的运行时类型为C,则应为 如果D是C并且只有 增加了C的不同方法。 这应该是安全的,不是吗?)

    一点也不。如果可以进行此转换,则可以编译试图对此对象调用“added methods”之一的代码,该代码在运行时将失败,因为该方法在C中不存在。

    我认为您正在想象,强制转换将检测到C中“缺少”的方法,并将它们自动委托给D。我怀疑这是可行的,尽管我不能说出语言设计的含义。

    在我看来,解决你的问题的办法是:

    定义类D,扩展C并实现I
    定义一个构造函数d(c c),它基本上将给定c对象的状态克隆到一个新的d对象中。
    D对象可以传递给现有的代码,因为它是C,并且可以传递给需要I的代码,因为它是I

        5
  •  1
  •   Michael Borgwardt    17 年前

    我相信你想要的是可能的 java.lang.reflect.Proxy 实际上,我为当前的项目做了类似的事情。然而,这是一项相当大的工作,并且由此产生的“混合对象”可能暴露出奇怪的行为(因为对它们的方法调用被路由到不同的具体对象,所以当这些方法试图彼此调用时会出现问题)。

        6
  •  0
  •   Nikolay Ivanov    17 年前

    我认为你不能这么做,因为Java是严格类型化的。我相信它可以用Ruby和Python这样的语言来实现,使用mixin。

    对于Java来说,它无疑是适配器设计模式的一种很好的用法(它早就被提出为“包装器”对象)。

    推荐文章