Java 扩展接口以更改合同,而不是API

Java 扩展接口以更改合同,而不是API,java,interface,Java,Interface,(我不确定标题术语是否正确。) 假设我试图为可读、可写和可读写的“属性”创建一些抽象。根据具体情况,我可能希望只接受可读属性、只接受可写属性,或者同时接受可读和可写属性。但是,假设我希望两种类型的属性都从同一超类型派生出它们的核心方法,但我也希望维护类型安全(例如,如果我请求一个可读属性,我希望得到一个可读属性) 以下是属性超级接口的外观: public interface Property { // Readable property core methods /**

(我不确定标题术语是否正确。)

假设我试图为可读、可写和可读写的“属性”创建一些抽象。根据具体情况,我可能希望只接受可读属性、只接受可写属性,或者同时接受可读和可写属性。但是,假设我希望两种类型的属性都从同一超类型派生出它们的核心方法,但我也希望维护类型安全(例如,如果我请求一个可读属性,我希望得到一个可读属性)

以下是
属性
超级接口的外观:

public interface Property {
    // Readable property core methods

    /**
     * Blah blah...
     * @throws UnsupportedOperationException if this property is not readable.
     */
    X readAsX();
    ...

    // Writable property core methods

    /**
     * Blah blah...
     * @throws UnsupportedOperationException if this property is not writable.
     */
    void writeX(X value);
    ...
}
需要注意的重要一点是,如果
属性
不可读/写,则指定它酌情抛出
UnsupportedOperationException

现在,以下是定义
ReadableProperty
的合适方法吗?(
writeableproperty
的定义类似。)

注:未添加任何新方法;所有的改变是现有的方法有一个更严格的规范。这种设计是否适合所描述的情况


(注意:这个场景是虚构的。我更关心这个想法,而不是它的具体应用。)

为什么不简单地使用两个抽象类,每个抽象类只实现一个方法

public abstract class ReadableProperty implements Property {
// Readable property core methods
// Writable property core methods

/**
 * Always throws UnsupportedOperationException: this property is not writable.
 */
@Override
final void writeX(X value) {
    throw new UnsupportedOperationException();
}
}


实际上,您正在实现一个接口的方法,而不是为接口中新引入的签名定义默认行为(这是引入默认修饰符的主要原因)

为什么不使用两个抽象类,每个抽象类只实现一个方法呢

public abstract class ReadableProperty implements Property {
// Readable property core methods
// Writable property core methods

/**
 * Always throws UnsupportedOperationException: this property is not writable.
 */
@Override
final void writeX(X value) {
    throw new UnsupportedOperationException();
}
}


实际上,您正在实现一个接口的方法,而不是在接口中为新引入的签名定义默认行为(这是引入默认修饰符的主要原因)

我将拥有一个抽象类属性,在读和写之间保存公共操作,扩展此抽象类并实现读取操作的ReadProperty和扩展此抽象类并实现读取操作的WriteProperty

通过在接口中使用不受支持的操作,您违反了Liskov替换原则。重新审视坚实的原则


您可以将这个抽象类作为参数传递给函数,并在处理时检查它是否实现了读接口或写接口。

我会有一个抽象类属性,它包含读和写之间的公共操作,扩展此抽象类并实现读取操作的ReadProperty和扩展此抽象类并实现读取操作的WriteProperty

通过在接口中使用不受支持的操作,您违反了Liskov替换原则。重新审视坚实的原则


您可以将此抽象类作为参数传递给函数,并在处理时检查它是否实现了读接口或写接口。

这不充分的一个明显原因是可以重写
default
方法。至于其余部分,我会让可读写的决定在具体的实现级别上确定。拥有一个只增加这些可读写属性的特殊性的接口真的没有多大意义。你的方法是合法的。列表的实现中也使用了同样的方法,其中有些操作是可选的。但这会导致头痛。如何知道实现是否实现了可选操作之一?对我来说,这似乎是一种反模式。最好有WritableProperty/ReadableProperty接口,
接口属性扩展了WritableProperty,ReadableProperty
@ernest_k是的,这是值得关注的部分:从技术上讲,没有什么可以阻止
ReadableProperty
的可写性,反之亦然。然后,当一个接口指定一个方法应该返回所描述类型的特定整数属性时,例如,没有什么可以阻止实现者返回一个随机整数。尽管如此,还是有更好的方法可以做到这一点。不过,在java集合中使用这种方法很有意思。这种方法不足的一个明显原因是,
default
方法可以被覆盖。至于其余部分,我会让可读写的决定在具体的实现级别上确定。拥有一个只增加这些可读写属性的特殊性的接口真的没有多大意义。你的方法是合法的。列表的实现中也使用了同样的方法,其中有些操作是可选的。但这会导致头痛。如何知道实现是否实现了可选操作之一?对我来说,这似乎是一种反模式。最好有WritableProperty/ReadableProperty接口,
接口属性扩展了WritableProperty,ReadableProperty
@ernest_k是的,这是值得关注的部分:从技术上讲,没有什么可以阻止
ReadableProperty
的可写性,反之亦然。然后,当一个接口指定一个方法应该返回所描述类型的特定整数属性时,例如,没有什么可以阻止实现者返回一个随机整数。尽管如此,还是有更好的方法可以做到这一点。不过,在java集合中使用这种方法很有趣。