使用第三方抽象类就好像它是一个接口?

时间:2012-05-28 00:27:17

标签: java polymorphism

在我正在使用的第三方库中,有以下几个层次结构:

public abstract class Foo
{
    // Class is public in the Java sense and public in the library's API
}

public class FooImpl extends Foo
{
    // While this class is public in the Java sense, it is
    // NOT part of the public API and is not even documented
    // Library functions that hand back instances of this class
    // hand them back as type Foo
}

库中的各种方法对Foo类型的事物进行操作。 Foo文档说用户可以扩展Foo以进行具体实现,并且(显然)库提供了具体的实现。

我很满意库提供的实现,除了一个方法,我想改变它的行为。但是我提供的等级制度让我感到沮丧。

如果 Foo是一个界面(它不是!),我只会这样做:

public FooWrapper implements Foo
{
    private Foo wrappedImpl;

    public FooWrapper(Foo toBeWrapped) {
        wrappedImpl = toBeWrapped;
    }

    List<Whatever> methodIWantToTweak() {
        List<Whatever> list = wrappedImpl.methodIWantToTweak();
        do_something_to_list(list);
        return list;
    }

    Something methodThatsOk() {
        return wrappedImpl.methodThatsOk();
    }

    // similar delegations for remaining methods
}

但是因为它一个接口我不能这样做,或者至少不能干净利落地做。

我能想到的唯一事情是:

1)扩展API非公共类FooImpl并覆盖我想要调整的方法。

2)做类似的事情:

public class FooWrapper extends Foo
{
    private Foo wrappedImpl;

    public FooWrapper(Foo toBeWrapped) {
        super();
        wrappedImpl = toBeWrapped;
    }

    List<Whatever> methodIWantToTweak() {
        List<Whatever> list = wrappedImpl.methodIWantToTweak();
        do_something_to_list(list);
        return list;
    }

    Something methodThatsOk() {
        return wrappedImpl.methodThatsOk();
    }

    // Override all non-final public, protected, and package-local
    // methods and delegate them to wrappedImpl
}

这两种方法都闻起来像我。第一个问题是它依赖于一个它不应该知道的类,以及哪个类可以在库的未来版本中更改/消失/重命名。第二个问题是FooWrapper的超类部分实际上没有被使用,并且不可能覆盖Foo的任何最终或私有方法(这将导致问题,因为在那些情况下,一个人无法委托给wrappedImpl)。

我想我必须采用第一种方法,因为至少它会给出正确的行为,而第二种可能会以潜在的邪恶,微妙的方式被打破,具体取决于Foo的内部细节

那我是不是运气不好?我还有哪些其他方法/想法?

2 个答案:

答案 0 :(得分:3)

如果您不需要覆盖任何Foo的最终或受保护(见下文)方法,我会采用第二种方法:将Foo视为接口并执行操作在那种情况下你会做的。优点是您不依赖于可以更改的FooImpl

final的{​​{1}}和private方法不是问题,因为您无法覆盖FooFooImpl是{接口,无论如何。另外,我认为您的意思是Foo而不是protected

如果您 需要覆盖private方法,则需要采用第一种方法。

答案 1 :(得分:2)

我想不出任何其他不会变得更臭的方法! (反思会起作用,但在这种情况下,它会比你试图避免的问题更糟糕。)

我认为第二种方法是最好的。如果Foo抽象类被设计为公共类,那么它不应该有令人讨厌的内部细节可能会让你失望。如果是这样,他们的设计就错了。

请注意,因为您要为“真正的”Foo实例创建包装类:

  • 您可以忽略抽象类为“真正的”Foo子类提供的大多数功能。

  • 您可以忽略由Foo级属性表示的任何状态。

  • 您可以在API中存根不需要在应用程序中使用的方法;例如将它们编码为UnsupportedOperationException

所有这些都有助于降低问题的复杂性。

相关问题