我有一个界面:
public interface I {
getBar();
}
我有2类:A
和B
实现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语言中消失了
答案 0 :(得分:1)
只需将实例的东西移动到通用的追加函数中
private void append(I item) {
if (item instanceof A) ...
if (item instanceof B) ...
}
然后您就可以使用
items.foreach(this::append);
答案 1 :(得分:0)
如果您采用更多面向对象的方法,
interface Appender{ void append(I item); }
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());
是的,它仍然是多分支的,必须运行更多指令才能获得相同的结果:)