4

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

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
}

库中的各种方法对类型的事物进行操作FooFoo文档说用户可以扩展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-non-public 类 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.

那我是不是运气不好?我忽略了哪些其他方法/想法?

4

2 回答 2

3

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

finalprivate方法Foo都不是问题,因为无论如何您都无法覆盖其中的那些FooImpl或如果Foo是接口。另外,我认为您的意思是protected代替private.

如果您确实需要覆盖protected方法,则需要使用第一种方法。

于 2012-05-28T00:38:03.693 回答
2

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

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

请注意,由于您正在为“真实” Foo 实例创建包装类:

  • 您可能会忽略抽象类为“真正的” Foo 子类提供的大部分功能。

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

  • 您可以在 API 中删除不需要在应用程序中使用的方法;例如,对它们进行编码以抛出UnsupportedOperationException.

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

于 2012-05-28T00:38:20.140 回答