具有可选组件的接口有什么好的设计?

Mic*_*and 5 java oop design-patterns

假设我有一个支持一些潜在操作的接口:

interface Frobnicator {
    int doFoo(double v);
    int doBar();
}
Run Code Online (Sandbox Code Playgroud)

现在,某些实例仅支持这些操作中的一个或另一个.他们可能都支持两者.客户端代码不一定会知道,直到它实际上得到一个从相关工厂,通过依赖注入,或者是任何一个从获得的情况.

我看到了一些处理这个问题的方法.一,这似乎是Java API中所采取的一般策略,是只对界面如上图所示,并有不支持的方法提高UnsupportedOperationException.然而,这样做的缺点是不能快速失败 - 客户端代码无法判断它是否doFoo会在尝试调用之前工作doFoo.

这可以使用supportsFoo()supportsBar()方法进行扩充,如果相应的do方法有效,则定义为返回true .

另一种策略是因式分解doFoodoBar方法融入FooFrobnicatorBarFrobnicator分别的方法.null如果操作不受支持,则会返回这些方法.为了防止客户端代码进行instanceof检查,我Frobnicator按如下方式定义了一个接口:

interface Frobnicator {
    /* Get a foo frobnicator, returning null if not possible */
    FooFrobnicator getFooFrobnicator();
    /* Get a bar frobnicator, returning null if not possible */
    BarFrobnicator getBarFrobnicator();
}

interface FooFrobnicator {
    int doFoo(double v);
}

interface BarFrobnicator {
    int doBar();
}
Run Code Online (Sandbox Code Playgroud)

另外,FooFrobnicator并且BarFrobnicator可以扩展Frobnicatorget*方法可能会被重新命名as*.

这个问题的一个问题是命名:Frobnicator真的不是frobnicator,它是一种获取frobnicators的方式(除非我使用as*命名).它也有点笨拙.命名可能更复杂,因为Frobnicator将从FrobnicatorEngine服务中检索.

有没有人对这个问题有一个好的,最好被广泛接受的解决方案?有适当的设计模式吗?访问者在这种情况下是不合适的,因为客户端代码需要特定类型的接口(并且如果它无法获得它,最好应该快速失败),而不是调度它获得的对象类型.是否支持不同的功能可能会因各种因素而异 - 实现,该实现Frobnicator的运行时配置(例如,doFoo只有在启用某些系统服务时才支持Foo),等等.

更新:运行时配置是此业务中的另一个猴子扳手.可以通过FooFrobnicator和BarFrobnicator类型来避免这个问题,特别是如果我使用Guice-modules-as-configuration,但它会将复杂性引入其他周围的接口(例如生产Frobnicators的工厂/构建器)首先).基本上,生成frobnicator的工厂的实现是在运行时配置的(通过属性或Guice模块),我希望它能让用户很容易地说"将这个frobnicator提供者连接到这个客户端" .我承认这是一个潜在的固有设计问题的问题,我也可能会过度思考一些泛化问题,但我

Mat*_*ynn 3

如果您说类 FooImpl 实现了接口 Foo,但它并没有真正实现所有 Foo,我认为您有问题。该接口应该是一个契约,指示实现类(至少)实现哪些方法。

如果有东西调用 FooFactory 来获取 Foo 对象,则该对象应该能够执行 Foos 所做的事情。

那么,你要从那里去哪里呢?我建议你的组合想法是一个很好的想法,使用继承稍微少一些。

组合将完全按照getFooFrobnicator()getBarFrobnicator()方法进行工作。如果您不喜欢这样,那么您Frobnicator并没有真正的 frobnicate,请将其称为FrobnicatorHolder.

继承将使您Frobnicator仅包含所有 Frobnicators 具有的方法,并且子接口将具有附加方法。

public interface Frobnicator{
   public void frobnicate();
}

public interface FooFrobnicator{
   public void doFoo();
}

public interface BarFrobnicator{
   public void doBar();
}
Run Code Online (Sandbox Code Playgroud)

然后你就可以使用了if (frobnicator instanceof FooFrobnicator) { ((FooFrobnicator) frobnicator).doFoo() },生活还要继续。

优先考虑组合而不是继承。你会更快乐。