【问题标题】:Is it true that we can replace all classes that implement multiple interfaces?我们真的可以替换所有实现多个接口的类吗?
【发布时间】:2016-07-24 23:25:36
【问题描述】:

我认为我们总是可以用多个接口替换类,例如:

public class C implements A,B{
}

换成每个类最多包含一个接口的另一个版本,是不是真的(我只想问“如果我们可以……”,而不是“如果我们应该……”)?

考虑 C 覆盖了来自 A 的方法 a() 和 b() B:

public class C implements A,B{
    @override
    public void a(){
    }

    @override
    public void b(){
    }
}

这是一个不断变化的单一责任原则,因为更改 a() 或 b() 都需要更改 C,相反我们可以将 A 和 B 包装为一个独立的类:

public class ConcreteA implements A{
    @override
    public void a(){
    }
}

public class ConcreteB implement B{
    @override
    public void b(){
    }
}

public class C{
    ConcreteA a;
    ConcreteB b;
}

是真的吗?

即使你的类有一个需要2个接口的单一职责,仍然可以将其重写为仅在每个类中成为一个接口,例如,原始版本:

public class C implements A,B{
    @Override
    public void a(){
    }

    @Override
    public void b(){
        a();
    }
}

在这种情况下,我们可以将其重写为:

public class ConcreteA implements A{
    @Override
    public void a(){
    }
}

public class C implements B{
    ConcreteA a;
    @Override
    public void b(){
        a.a();
    }
}

所以我的问题是,我们是否可以将所有包含两个以上接口的类替换为最多只包含一个接口的版本?

如果没有,什么情况下需要实现多个接口才能完成任务?

【问题讨论】:

  • 不,这不是真的。如果其中一个接口是Serializable怎么办?
  • 顺便说一下,根据您的示例,您的意思是“至少 2”(>= 2),而不是“超过 2”(> 2)。
  • 您的意思是public class C extends ConcreteA implements B 还是在定义 B 时它也在定义中实现了 A?以便在 C 类的实例上可以访问方法 a() 和 b()?
  • 理论上你可以拆分许多这样的类,但实际上经常需要实现多个接口,例如当您需要在某些数据类上实现CloneableSerializable 时。或者考虑a()b() 必须对相同的实例数据进行操作的情况。您可能可以将该数据移至第三类或ConcreteAConcreteB,但这不会减少耦合,这是 srp 的目标。

标签: java oop interface language-agnostic


【解决方案1】:

实现多个接口或使用多重继承是否违反单一职责原则的问题之前已经讨论过,例如here。对此似乎没有明确的共识。在我看来,您使用的 SRP 的定义太严格了。

cmets中提到的Serializable接口是一个特例,因为它是一个不声明任何方法的标记接口。但也有像Runnable 这样的其他接口,通常单独使用是没有意义的。

回到您的问题:是的,理论上这是可能的,但在不违反 DRY 等其他重要原则的情况下(不要重复自己)。想想一个类,它不仅实现了在实现的接口中声明的方法,而且还实现了它自己的方法:

public class C implements A,B {
    public void a(){}
    public void b(){}
    public void c(){}
}

拆分结果:

public class CA implements A {
    public void a(){}
    public void c(){}
}

public class CB implements B {
    public void b(){}
    public void c(){}
}

现在方法c()被复制了。是的,您可以使用额外的接口C 或将此方法放入某种实用程序类中,但我想说这通常不会改进设计。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-30
    • 2014-02-11
    • 2015-11-24
    • 2018-04-04
    • 2020-11-04
    • 2015-02-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多