Java接口设计:接口 vs 布尔方法

3

我在以下两种设计之间做出选择。你会推荐哪一种?为什么?

我对第二种方法中在接口中放置get/set方法感到怀疑。你有任何意见吗?

public class Foo {
    Time time;
    boolean hasTime();
    Time getTime() { return time; }
    void setTime() { this.time = time; }
}

public class Bar extends Foo {
    boolean hasTime() { return true; }
}

public class Baz extends Foo {
    boolean hasTime() { return false; }
}


main() {
    for (Foo foo : foos) {
        if (foo.hasTime()) {
            // do something
        }
    }
}

vs

public class Foo {
}

public class Bar extends Foo implements TimedObject {
    Time time;
    Time getTime() { return time; }
    void setTime() { this.time = time; }
}

public interface TimedObject {
    Time getTime();
    void setTime();
}

main() {
    for (Foo foo : foos) {
        if (foo instance of TimedObject) {
            // do something
        }
    }
}
4个回答

4
第二种方法显然更好。在第一种方法中,Bar和Baz类中都存在getter和setter,并且可以被调用...不管hasTime()返回什么!您可以在Baz中重写getter和setter,使它们抛出(例如)OperationNotSupported异常。但即使如此也有点棘手:如果比较程序使用两个版本的方式,第一个版本需要您记得调用hasTime(),而第二个版本中编译器会告诉您是否忘记将类型强制转换为与TimedObject兼容的类型。第一个版本违反了可替换性原则,因为Baz的行为与其超类Foo不兼容。

如果超类文档规定setTime()将设置任何对象的时间,只要该对象的hasTime()曾经返回过true,那么一个对象可以满足这个约定,即使它在setTime()中不能执行任何有用的操作,只需通过让其hasTime()方法始终返回false。没有违反LSP(Liskov Substitution Principle)的情况。问题是是否会有包含一些hasTime()返回true,另一些返回false的集合,并且希望在hasTime()返回true的对象上使用与时间相关的方法。如果确实希望这样做... - undefined
...然后hasTime()方法可能更清晰。在某些情况下,可以通过使用hasTime方法并定义一个继承自FooFooWithTime类,并重写hasTime()方法返回true来获得“两全其美”的效果。这将允许在混合集合中以高效的方式使用事物,而无需进行类型转换,同时还可以根据类型验证事物对“时间”函数的支持是否有帮助(在将可能支持这些方法的事物传递给需要它们的事物之前,需要进行强制转换)。 - undefined

2
我更喜欢第二个方案,因为实现的接口可以给你一个类型而不管实际对象类型,并保证可用一系列方法(由接口定义的“契约”)。通常情况下,不要为getters访问的属性放置 boolean hasXX() 方法,因为通常您应该测试 if (Y.getX()!= null) 以测试属性是否已设置或具有任何值。

1

我也喜欢第二个选项。此外,如果您对接口中的Getter和Setter有疑问,您可以考虑将此接口拆分为两个:

public interface TimedObject {
   Time getTime();
}
public interface MutableTimedObject extends TimedObject {
   void setTime(Time time);
}
...
if (foo instance of TimedObject) {
        // do something
        if (foo instance of MutableTimedObject) {
                // change time
        }
}

+1为这个巧妙的技巧... 虽然一个更好的主意是完全禁止可变性! - undefined

0

这真的取决于你问我的意见。接口的好处是,你可以将代码移动到另一个类中,并应用组合而不是继承。


第一种方法的好处是什么? - undefined
第一种方法的优点是可以应用真正的多态性。例如,通过抽象等强制子类实现。默认实现。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接