【问题标题】:How to deprecate an inner interface如何弃用内部接口
【发布时间】:2018-05-09 21:03:18
【问题描述】:

我需要弃用 Java SDK 中的 API 以使其更通用。但我不知道如何处理以下情况:

public class AdoptDog {
    public interface OnDogAdoption {
        public void onDogAdoption(String dogName);
    }
    public void adoptDog(final String dogName, OnDogAdoption callbackObj) {
        // Perform asynchronous tasks...
            // Then call the callback:
            callbackObj.onDogAdoption(dogName);
    }
}

SDK 用户调用如下:

AdoptDog adoptDog = new AdoptDog();
adoptDog.adoptDog("Snowball", new OnDogAdoption {
    @Override
    public void onDogAdoption(String dogName) {
        System.out.println("Welcome " + dogName);
    }
};

我想从 Dog 推广到 Pet 并弃用提及 Dog 的 API。为了向后兼容,当我弃用 API 时,上面采用 Snowball 的代码 sn-p 不应更改。

我如何尝试弃用 Dog API:

// Introduce Pet API

public class AdoptPet {
    public interface OnPetAdoption {
        public void onPetAdoption(String petName);
    }
    public void adoptPet(final String petName, OnPetAdoption callbackObj) {
        // Perform asynchronous tasks...
            // Then call the callback:
            if (callbackObj instanceof OnDogAdoption) {
                ((OnDogAdoption) callbackObj).onDogAdoption(petName);
            }
            else {
                callbackObj.onPetAdoption(petName);
            }
    }
}

// Dog API now extends Pet API for backward compatibility

@Deprecated
public class AdoptDog extends AdoptPet {
    @Deprecated
    public interface OnDogAdoption extends AdoptPet.OnPetAdoption {
        @Deprecated
        public void onDogAdoption(String dogName);
    }
    @Deprecated
    public void adoptDog(final String dogName, OnDogAdoption callbackObj) {
        super.adoptPet(dogName, callbackObj);
    }
}

问题是它不完全向后兼容。 SDK 的用户必须实现 AdoptPet.OnPetAdoption.onPetAdoption() 否则会出现编译器错误:

AdoptDog adoptDog = new AdoptDog();
adoptDog.adoptDog("Snowball", new OnDogAdoption {
    @Override
    public void onDogAdoption(String dogName) {
        System.out.println("Welcome " + dogName);
    }

    // PROBLEM: How avoid customers having to implement this dummy method? 
    @Override
    public void onPetAdoption(String petName) {
        assert("This code should not be reached");
    }
};

是否有其他方法可以弃用 AdoptDog(特别是 OnDogAdoption)并保持完全的向后兼容性?

【问题讨论】:

  • 如果您使用的是 java 8 或更高版本,则可以使用@Stewart 建议的默认方法实现来完成,否则我认为除了重大更改之外没有其他方法。

标签: java deprecated deprecation-warning


【解决方案1】:

Java 8 允许您指定default 方法实现。你可以用它来帮助你,例如:

@Deprecated
public interface OnDogAdoption extends AdoptPet.OnPetAdoption {
    @Deprecated
    void onDogAdoption(String dogName);

    default void onPetAdoption(String petName) {
        onDogAdoption(petName);
    }
}

通过具有默认实现,客户端代码将不需要实现它(但如果他们愿意也可以),因此不会出现编译错误。


注意: All interface methods are public by default - in fact they can only be public - there's no need to specify that.

【讨论】:

  • 关于你的笔记,有时明确一点是有帮助的
  • @pushkin 取决于您习惯的约定。在这里,我的目标是简短,但想抵消有人抱怨我没有正确复制 OP 的代码。叹息,我猜你总是以这样或那样的方式得到评论;)
  • @NiVeR 我将为此添加一个明确的注释。但说真的,Java 7 的生命周期结束是 2015 年 4 月。
  • @AndyTurner 已修复
  • @Stewert 我知道一些仍然以 Java 5 为目标的软件。一些企业仍在使用 Java 7。仅仅因为某些东西当前没有被维护并不意味着它是无关紧要的。听说过遗留软件吗?他可能正在尝试修复预期在 Java 5 环境中运行的旧软件。
【解决方案2】:

您不扩展OnPetAdoptionOnDogAdoption 不是 OnPetAdoptionOnPetAdoption 也可以处理猫的收养。 OnDogAdoption 不行。

我建议您将OnDogAdoption 包装在OnDogAdoptionDispatcher 中,并使用该调度程序调用新方法,例如:

@Deprecated
public class AdoptDog extends AdoptPet {
    @Deprecated
    public interface OnDogAdoption {
        @Deprecated
        public void onDogAdoption(String dogName);
    }

    private static class DogAdoptionDispatcher implements AdoptPet.OnPetAdoption {
            final OnDogAdoption target;
            public DogAdoptionDispatcher(OnDogAdoption target) {
                this.target = target;
            }
            @Override
            public void onPetAdoption(String petName) {
                target.onDogAdoption(petName);
            }
    }

    @Deprecated
    public void adoptDog(final String dogName, OnDogAdoption callbackObj) {
        super.adoptPet(dogName, new DogAdoptionDispatcher(callbackObj));
    }
}

这样,您仍然具有向后兼容性和干净的新界面。

如果您使用的是 Java 8 或更高版本,则不需要单独的类,您可以这样做

public void adoptDog(final String dogName, OnDogAdoption callbackObj) {
    super.adoptPet(dogName, callbackObj::onDogAdoption);
}

【讨论】:

  • 谢谢,一个优雅的解决方案。如果有人需要有关双冒号语法的文档,请访问docs.oracle.com/javase/tutorial/java/javaOO/…。它似乎没有正式名称,但有人称它为双冒号运算符。
  • 名称为方法引用。
  • 不应该 AdoptDog 不扩展 AdoptPet 原因与您在上面所做的相同,即“A OnDogAdoption 不是 OnPetAdoption”?也许AdoptDog 应该分派给AdoptPet 的私有实例。
猜你喜欢
  • 2017-04-04
  • 2015-03-29
  • 2011-09-14
  • 1970-01-01
  • 2011-12-03
  • 1970-01-01
  • 1970-01-01
  • 2011-01-24
  • 2015-02-26
相关资源
最近更新 更多