具有多个类的方法实现相同的接口

时间:2020-07-29 10:20:41

标签: java java-8

我有一个界面:

public interface I {
   getBar();
}

我有2类:AB实现I

我想做的是:

public void foo(List<I> items) {
   for (I item : items){
      if (item instanceof A) this.append((A) item);
      if (item instanceof B) this.append((B) item);
   }
}

从Java 8开始,是否有某些东西让我没有instanceof的列表,而是这样称呼它?

items.foreach(this::append);

注意: 我可以做类似item.add(this)的事情,将其自身附加到this上,但是然后我将在对象上调用方法来修改参数(并且仅对参数进行修改),但这是罗伯特·C(Robert C)所说的错误做法。马丁的“清洁代码”:

参数最自然地解释为函数的输入。

任何迫使您检查功能签名的事情都等同于重复使用。这是一种认知障碍,应避免。在面向对象编程之前的日子里,有时必须要有输出参数。但是,输出参数的大部分需求在OO语言中消失了

4 个答案:

答案 0 :(得分:1)

只需将实例的东西移动到通用的追加函数中

private void append(I item) {
  if (item instanceof A) ...
  if (item instanceof B) ...
}

然后您就可以使用

items.foreach(this::append);

答案 1 :(得分:0)

如果您采用更多面向对象的方法,

  1. 定义Appender
interface Appender{
  void append(I item);
}
  1. 为A B创建附加程序,不执行任何操作的默认附加程序
  2. 将追加程序放入地图Map
  3. 将代码更改为
 for (I item : items){
     appenders.getOrDefault(item.class,DEFAULT_APPENDER).append(item);
 }

答案 2 :(得分:0)

您正在颠倒地考虑它。

您的类获取I的这些实例,并根据类型具有不同的重载方法。这种重载意味着它需要了解所有实现,以为每个实现提供不同的重载。

显然,问题在于列表必须随着实现的添加而增长。

解决方案是使I实现负责了解它们的附加方式。

public interface I {
    Bar getBar(); /* you missed the return type, but anyway */

    void appendTo(SomeType foo);
}

您的方法变得简单

public void foo(List<I> items) {
   for (I item : items){
      item.appendTo(this); //or instead of this, some append-able instance 
   }
}

如果有人添加了I的新实现,则他们被迫编写append方法作为接口协定的一部分。

答案 3 :(得分:0)

实际答案:这是一个双重调度问题,以Java为中心的解决方案是Visitor Pattern,它有很多变化。

愚蠢的答案:只是踢,没有instanceof 这里

    private static final Map<Class<?>, Consumer<I>> DISPATCHER = Map.of(
      A.class, this::appendA,
      B.class, this::appendB
    );

    items.forEach(i -> DISPATCHER.get(i.getClass()).accept());

是的,它仍然是多分支的,必须运行更多指令才能获得相同的结果:)