java - 如何使两个具有相同名称、签名和返回类型的方法的类表现得像它们实现相同的接口(interface)一样

标签 java generics interface java-8

我会用一个例子来解释我的问题。

我有两个类(class) NumberGeneratorAppleNumberGeneratorOrange .它们都有相同签名和返回类型的方法 public Integer getNumber() .问题是他们没有实现相同的接口(interface),尽管这是合乎逻辑的。我可以使用此方法创建接口(interface)并修改这些类以实现它,但我不想这样做。这就是为什么。这些类是从 xml 自动生成的。在真实的例子中有几十个这样的类。我们必须不时生成它们,它会覆盖旧的。我不想在每一代之后手动更改每个类来实现接口(interface)。此外,对于从事同一项目的其他人,甚至一段时间后的我来说,这可能并不明显。
这是第一个类:

public class NumberGeneratorApple {
    public Integer getNumber(){
        return 9;
    }
}  

第二个:

public class NumberGeneratorOrange {
    public Integer getNumber(){
        return 19;
    }
}

虽然它们没有实现相同的接口(interface),但我需要以通用方式使用它们。我只想做这样的事情:

public class ClassThatOperates<T extends NumberGeneratorInterface> {
    T generator;

    public ClassThatOperates(T generator) {
        this.generator = generator;
    }

    public void doSomeOperation(){
        //Obviously it won't work for NumberGeneratorApple and NumberGeneratorOrange
        // because they do not implement NumberGeneratorInterface
        //And if I change "<T extends NumberGeneratorInterface>" to "<T>"
        // I cannot write method call "generator.getNumber()"
        System.out.print("The number with constant is: ");
        System.out.println(generator.getNumber() + 5);
    }
}

这是接口(interface)(我知道public不是必需的,默认是有的,我只是想强调一下):

public interface NumberGeneratorInterface {
    public Integer getNumber();
}

如你所见,不可能做这样的事情,因为 NumberGeneratorApple也不NumberGeneratorOrange工具 NumberGeneratorInterface .但是我想出了一些解决方案,但根据我的直觉,我认为它很差。我做了包装类:

public class NumberGeneratorAppleWrapper extends NumberGeneratorApple implements NumberGeneratorInterface {
}

public class NumberGeneratorOrangeWrapper extends NumberGeneratorOrange implements NumberGeneratorInterface {
}

这有点棘手。一开始可能并不明显,但是当您在此类之一的对象上调用 getNumber() 时,您实际上调用了如下内容:

@Override
public Integer getNumber() {
    return super.getNumber();
}

现在我可以这样调用它了:

public class Main {
    public static void main(String[] args) {
        ClassThatOperates<NumberGeneratorAppleWrapper> classThatOperatesApple = new ClassThatOperates<>(new NumberGeneratorAppleWrapper());
        ClassThatOperates<NumberGeneratorOrangeWrapper> classThatOperatesOrange = new ClassThatOperates<>(new NumberGeneratorOrangeWrapper());
        classThatOperatesApple.doSomeOperation();
        classThatOperatesOrange.doSomeOperation();
    }
}

我得到以下输出:

The number with constant is: 14
The number with constant is: 24

这种方法的优点而不是手动添加 implements NumberGeneratorInterface对于每个生成的类,我们不必在每一代之后重复相同的工作(这会覆盖旧类)。当生成产生一些新的附加类时,我们只需要添加一个新的包装器。

我知道在这种情况下我可以在 ClassThatOperates 中摆脱泛型并声明 NumberGeneratorInterface generator;没有<T extends...>等等(我什至应该)这样代码会更简单,但我想让这个例子与我在一些真实项目中发现的非常相似。我写道:我有,我做了,我想出了等等,但实际上它是基于我在某个项目中找到的已经存在的代码。

我的问题是:
1.有没有更好的解决方案?
2. 这个解决方案是所谓的“坏味道”吗?
3.如果我必须使用这样的解决方案,也许我的整个方法都是错误的?
4. 如果没有更好的解决方案,即使整个方法都是错误的,这段代码有什么可以改进的(包括摆脱泛型)?

最佳答案

  1. Is there a better solution?

我觉得你的解决方案不错。您已经使用了 Adapter Pattern ,它使用现有功能来符合其他不相关的接口(interface)。不改变NumberGeneratorAppleNumberGeneratorOrange ,您已将这些类的功能调整为 NumberGeneratorInterface .

更一般地说,您可以让具有不同签名的现有方法适应接口(interface),例如如果你有

public class NumberGeneratorApple {
    public Integer getAppleNumber(){
        return 9;
    }
}

然后你的适配器类将显式调用 getAppleNumber在实现接口(interface)时。

public class NumberGeneratorAppleWrapper extends NumberGeneratorApple implements NumberGeneratorInterface {
    @Override
    public Integer getNumber() {
        return getAppleNumber();
    }
}
  1. Is this solution a so called "bad taste"?

这个解决方案没有留下任何不好的味道。适配器模式是一种成熟的软件设计模式。

  1. If I have to use such solution maybe my whole approach is wrong?

如果您无法更改现有类,例如 NumberGeneratorApple ,那么适配器模式就是要走的路。如果您可以更改它们,那么只需让这些类直接实现必要的接口(interface)即可。

public class NumberGeneratorApple implements NumberGeneratorInterface {
    @Override
    public Integer getNumber() {
        return 9;
    }
}

或者,如果方法签名不同:

public class NumberGeneratorApple implements NumberGeneratorInterface {
    public Integer getAppleNumber() {
        return 9;
    }

    @Override
    public Integer getNumber() {
        return getAppleNumber();
    }
}
  1. If there is no better solution even if the whole approach is wrong what could be improved in this code (including getting rid of generics)?

如果你的类如NumberGeneratorApple确实只有一种方法,而不仅仅是为了这个问题的目的使用多种方法简化更复杂的类,那么您可以使用方法引用作为另一个答案所暗示的。而不是声明自己的接口(interface) NumberGeneratorInterface , 方法引用可以输入为 Supplier<Integer> .

public class ClassThatOperates {
    Supplier<Integer> generator;

    public ClassThatOperates(Supplier<Integer> generator) {
        this.generator = generator;
    }

    public void doSomeOperation(){
        System.out.print("The number with constant is: ");
        System.out.println(generator.get() + 5);
    }
}

然后您可以将其用作:

NumberGeneratorOrange ngo = new NumberGeneratorOrange();
ClassThatOperates cto = new ClassThatOperates(ngo::getNumber);
cto.doSomeOperation();

关于java - 如何使两个具有相同名称、签名和返回类型的方法的类表现得像它们实现相同的接口(interface)一样,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53509223/

相关文章:

java - java密码学中 'AGCM256-KW'的算法字符串是什么,用于Cipher.getInstance(String algo)?

java - joinPoint.proceed() 有什么作用?

generics - Kotlin List<T> 包含来自 T 以外类型的对象

c# - 如何检测一个对象是一个泛型集合,以及它包含哪些类型?

c# - F# Struct with Interface,C# 元数据不显示从 Interface 的继承

java - h :inputHidden? 中的 JSF 2.0 对象值

java - 如何在没有桌面环境的情况下从 Linux shell 运行 Java Swing 应用程序?

java - 将通用服务与其实现和子类型绑定(bind)

go - 如何在 Go 中迭代 []interface{}

c++ - 如何从实现与其他接口(interface)共享的接口(interface)的类继承