【问题标题】:How to design an extensible type infrastructure with dependencies among each other如何设计具有相互依赖关系的可扩展类型基础架构
【发布时间】:2010-01-09 16:10:39
【问题描述】:

我的应用程序是用于连接“模块”(通过模块端口)的编辑器。端口有端口类型。每个端口类型都有其关联的比较器。如果它们的属性满足比较器中实现的规则,则两种类型是兼容的。

我希望用户通过实现新的端口类型和如何连接它们的规则来扩展应用程序(通过 eclipse 扩展点基础设施)。

这意味着在运行时我只能与端口类型接口进行交互。没有具体的类是已知的。所有具体实现都由工厂返回。

我实现了这两个接口:

public interface IPortType {
    [many attributes]
}
public interface IComparator {
    public boolean isCompatible(IPortType source, IPortType target);

    // more interaction methods!
}

我目前的解决方案有点难看,因为通用 isCompatible(IPortType source, IPortType target) 方法是一种委托,必须在所有子类中重写。在这里简单地重载 isCompatible() 方法是行不通的。

但更大的缺点是违反了开闭原则:当需要支持一种新类型时,必须扩展所有具体的 Comparator 类。但是,当类型之间有更多的交互(如转换等)时,如何保持 规则类 的数量较少?我的意图是在一个类中保留一种类型的所有规则。

一个具体的比较器示例:

public class ATypeComparator implements IComparator {

    public boolean isCompatible(IPortType source, IPortType target) {
        if (!(source instanceof AType))
            return false;
        if (target instanceof BType)
            return isCompatible(source, (BType) target);
        if (target instanceof CType)
            return isCompatible(source, (CType) target);
    }

    public boolean isCompatible(AType source, BType target) {...}
    public boolean isCompatible(AType source, CType target) {...}
}

你会如何解决这个问题?

感谢您的任何建议!

【问题讨论】:

    标签: java interface modeling factory interaction


    【解决方案1】:

    我认为 IPortType 实现决定它是否与其他 IPortType 实现兼容是不正确的。这不是其责任的一部分。

    一个简单的解决方案是创建一个公共静态方法,例如在 PortTypeManager 类中,它知道两个 IPortType 实现是否兼容。这样,你 可以随时添加新类型,您只需在一个地方更改逻辑即可适应该新类型。

    但是,最终,这也不够,因为该方法应涵盖的案例数量像 n^2 一样增长。您需要为每个 IPortType 实现提供 getVersion() 或 getSignature() 之类的方法,该方法返回一条数据,您可以将其与类似的数据进行比较,以确定两个实现是否兼容。

    【讨论】:

    • 我同意兼容性检查不是类型责任的一部分。当新类型出现时,它还会导致许多地方进行更改。兼容性规则取决于类型可以具有的属性子集。有组合和算术测试来解决。处理这些操作的通用数据结构最终可能会实现另一种“编程语言”。但是你对签名的想法很有趣......
    【解决方案2】:

    如果您允许多态性来处理复杂性,您的实现似乎可以被清理。

    IPortType 上使用.compatibleTo() 方法不是更简单吗?如果你能做到这一点,每个实现都可以从本质上知道它支持的端点是什么?

    类似的东西:

    IPortType port1 = ...
    IPortType port2 = ...
    
    if (port.compatibleTo(port2)) {
        // do whatever
    }
    

    【讨论】:

    • 我同意这个解决方案不太复杂,但它会导致所有类型的变化相互兼容。并且不可能更改现有端口类型的代码,因为 Eclipse 的理念是扩展而不是更改。此外,兼容性规则应该与端口类型分开,因为知道可以用它做什么不是它的责任。
    • 兼容性是自反的吗?如果port1port2 兼容,那么port2 是否必须与port1 兼容?
    • 应该是自反的。无论如何,这似乎是一个观点问题。如果添加新的具体接口实现导致的工作超出预期,通常可以安全地认为存在代码异味,并且进行一些重构可能是个好主意。
    • 是的,我认为兼容性在这里是自反的。但在最坏的情况下,n 类型仍然存在 O(n^2) 规则。
    猜你喜欢
    • 1970-01-01
    • 2011-05-12
    • 1970-01-01
    • 2018-11-17
    • 2019-05-24
    • 1970-01-01
    • 1970-01-01
    • 2013-05-29
    • 2015-11-02
    相关资源
    最近更新 更多