簡體   English   中英

如何創建兩個具有相同名稱,簽名和返回類型的方法的類,就像它們實現相同的接口一樣

[英]How to make two classes which both have method with the same name, signature and return type behave like they would implement the same interface

我將以一個例子解釋我的問題。

我有兩個類NumberGeneratorAppleNumberGeneratorOrange 它們都具有相同簽名的方法,並返回類型public Integer getNumber() 問題是他們沒有實現相同的界面,盡管它是合乎邏輯的。 我可以使用此方法創建接口並修改這些類來實現它,但我不想這樣做。 這就是原因。 這些類是自動生成的,例如xml。 在實際例子中,有許多這樣的類。 我們必須不時地生成它們並覆蓋舊的。 我不想手動更改每個類以在每一代之后實現接口。 此外,對於在同一項目中工作的其他人,甚至在一段時間后對我來說,也可能不應該這樣做。
這是第一堂課:

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

第二個:

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

雖然他們沒有實現我需要以通用方式使用它們的相同接口。 我只是想做這樣的事情:

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);
    }
}

這是界面(我知道公共在那里沒有必要,它默認存在。我只想強調它):

public interface NumberGeneratorInterface {
    public Integer getNumber();
}

正如你所看到的,不可能做到這一點,因為NumberGeneratorAppleNumberGeneratorOrange都沒有實現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.有更好的解決方案嗎?
這個解決方案是否是一種所謂的“不良品味”?
如果我必須使用這樣的解決方案,那么我的整個方法可能是錯的?
4.如果沒有更好的解決方案,即使整個方法都是錯誤的,可以在此代碼中改進(包括刪除泛型)?

  1. 有更好的解決方案嗎?

你的解決方案對我來說很好。 您已使用適配器模式 ,它使用現有功能來符合其他不相關的接口。 在不更改NumberGeneratorAppleNumberGeneratorOrange ,您已將這些類的功能調整為NumberGeneratorInterface

更一般地說,您可以將具有不同簽名的現有方法適用於界面,例如,如果您有

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

然后,您的適配器類將在實現接口時顯式調用getAppleNumber

public class NumberGeneratorAppleWrapper extends NumberGeneratorApple implements NumberGeneratorInterface {
    @Override
    public Integer getNumber() {
        return getAppleNumber();
    }
}
  1. 這個解決方案是所謂的“壞味道”嗎?

這種解決方案沒有不好的味道。 適配器模式是一種成熟的軟件設計模式。

  1. 如果我必須使用這樣的解決方案,也許我的整個方法是錯的?

如果您無法更改現有的類(如NumberGeneratorApple ,則可以使用適配器模式。 如果你可以改變它們,那么讓這些類直接實現必要的接口。

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. 如果沒有更好的解決方案,即使整個方法都是錯誤的,可以在這段代碼中改進(包括擺脫泛型)?

如果您的類(如NumberGeneratorApple確實只有一個方法,並且不僅僅是為了解決此問題而使用多個方法簡化更復雜的類,那么您可以使用方法引用作為另一個答案。 可以將方法引用鍵入為Supplier<Integer> ,而不是聲明自己的接口NumberGeneratorInterface

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();

使用java8,您可以實例化一個自定義類

NumberGeneratorApple apple = new NumberGeneratorApple();

並從中創建一個通用供應商:

Supplier<Integer> numberGenerator = apple::getNumber;

然后你可以傳遞它或做任何你需要的東西:

Integer number = numberGenerator.get();
externalObject.execute(numberGenerator);

那聲音怎么樣?

考慮:

class ClassThatOperates
{
    final Supplier<Integer> m_generator;

    ClassThatOperates(Supplier<Integer> generator)
    {
        m_generator = generator;
    }
    void doSomething()
    {
        ...
        m_generator.get();
    }
}

NumberGeneratorApple nga = new NumberGeneratorApple();
ClassThatOperates cta = new ClassThatOperates(nga::generate);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM