【问题标题】:Strange interface design Java奇怪的界面设计Java
【发布时间】:2015-10-07 20:38:26
【问题描述】:

在工作中,我在一个java项目中遇到了如下设计:

考虑接口FooBarBaz如下:

interface Bar { public int a(); }

interface Baz { public int b(); }

interface Foo extends Bar, Baz { public int c(); }

现在,考虑类FooImpl

public class FooImpl implements Foo {

    private Bar bar;
    private Baz baz;

    public int a() {
        return bar.a();
    }
    public int b() {
        return baz.b();
    }
    public int c() {
        return 0;
    }
}

这种类层次结构的用例是什么?在我看来,这引入了很多样板文件并且在抽象方面并没有增加太多,除了将可能是大文件的文件分解成更小的文件。

【问题讨论】:

  • 取决于接口的具体语义及其作者。基本上 Foo 建立在 Bar 和 Baz 上(适用于 Bar 或 Baz 的代码也适用于 Foo)。 FooImpl 实现了一个这样的 Foo。这种设计是否有意义取决于在这些接口的消费者中实际使用 Bar、Baz 和 Foo。

标签: java inheritance design-patterns


【解决方案1】:

它允许这样的事情:

Foo foo = new FooImpl();
useBar(foo);

public void useBar(Bar bar) {
    bar.a();
}

这是否有用取决于真实的上下文。您的示例代码中的类和方法名称无意义,不支持理性判断。

要注意的另一件事是您的FooImpl 实际上是作为BarBaz 实例的某种包装器实现的。这不是(严格来说)界面设计问题。

【讨论】:

  • 感谢您的回复!我理解从多个接口扩展的情况,但我的问题应该更多地针对类的实现。在我看来,它引入了很多方法别名,并且破坏了 IDE 创建有意义的调用层次结构(通过创建无限循环)的能力。
  • 从(抽象的)设计角度来看,这些都不是特别糟糕的。 (IDE问题实际上是指向IDE设计中的一个缺点,而不是您正在查看的代码...)正如我在回答中所说,您需要在实际使用的上下文中查看这些东西-案子。您需要考虑它在做什么、为什么这样做以及替代方案是什么。
【解决方案2】:

我认为这是多重继承(Java 中不允许)的一种解决方法。您没有展示 BarBaz 的实现,但我们假设它们存在:

public class BarImpl implements Bar {

    @Override
    public int a() {
        return 1;
    }
}

public class BazImpl implements Baz {

    @Override
    public int b() {
        return 2;
    }
}

您都没有告诉我们BarBaz 属性是如何实例化并设置为FooImpl,因为如果按照您的问题中所述执行,您将在FooImpl.a()FooImpl.b()。同样,让我们​​想象一下如何实现这一点:

public class FooImpl implements Foo {

    private Bar bar; // better if final

    private Baz baz; // better if final

    // Constructor to properly initialize bar and baz
    public FooImpl(Bar bar, Baz baz) {
        this.bar = bar;
        this.baz = baz;
    }

    @Override
    public int a() {
        return bar.a();
    }

    @Override
    public int b() {
        return baz.b();
    }

    @Override
    public int c() {
        return 0;
    }
}

把所有东西都连接起来:

Bar bar = new BarImpl();
Baz baz = new BazImpl();

Foo foo = new FooImpl(bar, baz);

int one = foo.bar(); // 1
int two = foo.baz(); // 2

在某种程度上,FooImpl“继承”了BarImplBazImpl,尽管这是通过委托实现的。

【讨论】:

    【解决方案3】:

    这样做实际上只是使用其属性(bar 和 baz)“a”方法和“b”方法重定向 fooimpl

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-07
      • 2011-07-09
      • 1970-01-01
      • 2011-10-13
      • 2016-03-12
      • 1970-01-01
      • 1970-01-01
      • 2012-09-30
      相关资源
      最近更新 更多