【问题标题】:What is a better practice, to combine two interfaces through extension, or to cast an interface to its implementing type?什么是更好的做法,通过扩展组合两个接口,或者将接口转换为其实现类型?
【发布时间】:2012-07-25 13:38:38
【问题描述】:

假设我有两个接口和一个行为类:

public interface Creable {
    public boolean belongsToSystem();
    public List<Creable> getCreatedItems();
}

public interface HasDependencies {
    public void createDependencies();
    public void generateDependents();
}

public class CreableBehavior {
    private Creable creableObject;
    public CreableBehavior(Creable creableObject) {
         this.creableObject = creableObject;
    }

    public boolean hasBeenCreated() {
        return !creableObject.belongsToSystem() && !creableObject.getCreatedItems().contains(createdObject);
    }

还有这段代码:

Creable includedTab = new AdempiereTab(getIncluded_Tab_ID(),
                creableElements);
if (!new CreableBehavior(includedTab).hasBeenCreated) {
    includedTab.createDependencies();
    includedTab.getCreatedItems().add(includedTab);
    includedTab.generateDependents();
}

AdempiereTab 实现了 Creable 和 HasDependencies。问题是我需要同时使用接口 Creable 和 HasDependencies。
我应该这样投射吗:

if (!new CreableBehavior(includedTab).hasBeenCreated) {
    ((AdempiereTab)includedTab).createDependencies();
    includedTab.getCreatedItems().add(includedTab);
    ((AdempiereTab)includedTab).generateDependents();
}

或者我应该创建一个新的接口 CreableWithDependencies 来扩展两个接口并使用那个接口吗?

谢谢。

编辑:回答,我应该扩展接口,因为我不想依赖于实现类型。将它们结合起来可以让我使用具有相同代码的多种类型。

【问题讨论】:

    标签: java design-patterns interface


    【解决方案1】:

    有两种设计力量在起作用:使您的界面尽可能小,并尽量减少界面的数量。一般来说,大型接口以后重构的问题更大。

    如果您的接口已经在整个系统中使用,您可以将客户端代码拆分为单独的方法或类,创建一个扩展两个接口的接口CreableHasDependencies,或者直接使用类类型。

    如果这是您第一次使用接口,请将它们组合起来,因为接口属于客户端代码。

    【讨论】:

    • 这就是我通过组合它们的想法,但我担心它只会使代码库变得更混乱。谢谢。
    • 有两种设计力量在起作用:使您的界面尽可能小,并尽量减少界面数量。一般来说,大型接口以后重构的问题更大。
    • 对不起,我不明白“最小化接口数量”的说法。它不会违反 SOLID 原则吗?抱歉,我是静态类型语言的新手。
    【解决方案2】:

    仅基于查看创建 AdempiereTab 的代码 sn-p,我的第一个想法是,您可以简单地将其变量类型声明为 AdempierTab 而不是 Creable。您不需要使用抽象类型 Creable,因为您已经知道这是您将执行接口方法的类型。

    第二个想法,即使您知道 Creable 是 AdempiereTab(来自前面的代码行),最好在强制转换之前检查使用 instanceof 以避免任何异常。这证实了您应该将“includedTab”声明为 AdempiereTab。

    此外,在不太了解您的应用程序上下文的情况下,我确实对 HasDependencies 接口提出了质疑。纯粹基于名称,它本身似乎更像是一种方法。但它暴露的行为似乎令人困惑:create 和 generate 都返回 void。对我来说,这只是引出了这个界面是否经过深思熟虑的问题,也许需要重新设计成更清晰的东西。这可能会帮助您避免目前面临的问题。

    【讨论】:

    • createDependencies() 创建当前对象可能依赖的对象。例如,AdempiereTab 上的 createDependencies() 将创建一个窗口。 generateDependents() 应该创建依赖于这个的对象。在 AdempiereTab 的情况下,那将是 AdempiereField 的。您有什么改进建议?
    • 我的文章专注于命名,这对我来说在为客户创建 API(接口)时非常重要。因此,根据您的解释,我认为 HasDependencies 最好用 DependencyProvider 或 DependencyCreator 之类的名称来描述,或者类似于“我是一个可以创建、生成和返回您期望的必要依赖项的对象”。我鼓励改进这个接口的名称和描述,以证明它的存在。否则,正如我所建议的,也许设计可以重新设计。
    【解决方案3】:

    或者你可以这样做:

    AdempiereTab includedTab = new AdempiereTab(getIncluded_Tab_ID(),
                    creableElements);
    if (!new CreableBehavior(includedTab).hasBeenCreated) {
        includedTab.createDependencies();
        creableElements.getCreatedItems.add(includedTab);
        includedTab.generateDependents();
    }
    

    由于AdempiereTab 实现了这两个接口,您可以将AdempiereTab 传递给CreableBehavior's 构造函数。

    【讨论】:

    • 我想抽象出许多类型的 createDependencies()、add()、generateDependents() 循环。它应该适用于 AdempiereTab、AdempiereTable、AdempiereWindow 等......你看它是怎么回事。我需要它们共享一个通用接口,以便代码适用于所有人。
    猜你喜欢
    • 2023-02-21
    • 2020-11-22
    • 1970-01-01
    • 1970-01-01
    • 2017-02-16
    • 2013-09-25
    • 1970-01-01
    • 2013-09-30
    • 1970-01-01
    相关资源
    最近更新 更多