我应该将返回类型重命名为更通用的类型以便重用它吗?

时间:2010-02-25 20:04:05

标签: java oop refactoring

所以我犯了一个错误。

最初为API编写签名时,我创建了这样的内容:

public JellyBeanResult getJellyBeanReport();

现在,事实证明我想重新使用更具体的JellyBeanResult对象,因为它的功能,但让其他函数返回为不同进程命名的类型会让人感到困惑。我可以想到有几种方法可以解决这个问题。我可以将返回类型重命名为更通用的东西:

public GenericResult getJellyBeanReport();
public GenericResult getChocolateBarReport();

但这会破坏使用API​​的任何代码。我可以创建一个新的,更准确的命名类,它扩展了更接近新函数的SpecificResult:

public class ChocolateBarResult extends JellyBeanResult{};

public JellyBeanResult getJellyBeanReport();
public ChocolateBarResult getChocolateBarReport();

但这真的非常难看,如果我想再次使用返回类型,问题仍然存在。 如何在不破坏使用这些签名的代码的情况下清理这些签名以减少这些签名?

7 个答案:

答案 0 :(得分:6)

将核心功能从JellyBeanResult移至GenericResult并让JellyBeanResult扩展GenericResult:

public class JellyBeanResult extends GenericResult {}

public JellyBeanResult getJellyBeanReport();
public GenericResult getChocolateBarReport();

或者如果你想要完全一致:

public class JellyBeanResult extends GenericResult {}
public class ChocolateBarResult extends GenericResult {}

public JellyBeanResult getJellyBeanReport();
public ChocolateBarResult getChocolateBarReport();

答案 1 :(得分:4)

任何' true 'API的具体内容是它无法更改。您不能简单地更改/删除现有方法。您只能添加新功能。

我看到的唯一方法是你应该创建正确的方法集(比如你的GenericReport示例)并使用@Deprecated注释标记旧方法。

答案 2 :(得分:4)

你是对的,ChocolateBarResult扩展JellyBeanResult会很糟糕,因为JellyBeanResult可能有方法和字段(例如果冻豆的“颜色”)对巧克力棒有意义。所以,不要这样做。 : - )

如何创建新方法以返回正确的结果类型(GenericResult),然后将缩小的getJellyBeanReport()方法标记为@Deprecated,以阻止任何新用户使用它?

答案 3 :(得分:0)

假设您尚未发布当前版本的API,您是否可以重构使用通用接口和协变返回类型?

public interface ConfectionaryResult {...}
public class ChocolateBarResult implements ConfectionaryResult {...}
public class JellyBeanResult implements ConfectionaryResult {...}

public interface ConfectionaryInventory {
    ConfectionaryResult getReport();
}

public class JellyBeanInventory implements ConfectionaryInventory {
    JellyBeanResult getReport() {...}

    @deprecated "Use JellyBeanInventory.getReport() instead"
    JellyBeanResult getJellyBeanReport() {
        return getReport();
    }
}

public class ChocolateBarInventory implements ConfectionaryInventory {
    ChocolateBarResult getReport() {...}
}

我假设原始方法存在于库存类中 - 可能不是这种情况。

答案 4 :(得分:0)

我不确定你的目的是什么,但也许是这样的?

public JellyBeanResult getJellyBeanReport() {
    return getJellyBeanReport(JellyBeanResult.class);
}

public <T extends JellBeanResult> getJellyBeanReport(Class<T> resultType) {
    // get the correct report type
}

答案 5 :(得分:0)

<强>可能性:

  • 如果你只是想重用这些功能,你可以让所有其他类如ChocolateBarResult使用JellyBeanResult而不是扩展它。记住组合通常比继承更好。
  • 保留当前版本API的版本,以便现有用户可以使用。创建一个将进行更改的新版本,以便在用户需要新功能时升级其代码库。如果这样做,请创建某种更改指南,并可能将方法弃用一两个发布周期以允许进行更改。
  • 更好地规划API。 Dogfood你的代码。在拥有一组优秀的用户之前,请尽量不要将其作为API发布。

答案 6 :(得分:0)

如果您还要进行重构,那么考虑使JellyBeanResult成为扩展所需GenericResult接口的接口是有意义的。 (它本质上是一个标记接口,用于保留以前的返回类型。)现有的JellyBeanResult类成为您的第一个迭代GenericResultImpl类。

执行此操作后,您可以决定是否弃用现有方法以及如何以较低的风险替换它。