呼叫者:
switch (type){
case "creature":
Creature returnActor2 = getNextCreature();
boolean isEat2 = actOnNearby(getRightChromosome(Config.HardCode.creature), returnActor2.getLocation());
if (isEat2) {
actOnCreature(returnActor2);
}
break;
case "monster":
Monster returnActor3 = getNextMonster();
boolean isEat3 = actOnNearby(getRightChromosome(Config.HardCode.monster), returnActor3.getLocation());
if (isEat3) {
actOnMonster(returnActor3);
}
break;
}
它将调用以下两种方法:
private Monster getNextMonster() {
ArrayList<Actor> nearbyActors = getActors();
Monster mine = new Monster();
for (Actor a : nearbyActors) {
if (a instanceof Monster) {
mine = (Monster) a;
}
}
return mine;
}
private Creature getNextCreature() {
ArrayList<Actor> nearbyActors = getActors();
Creature mine = new Creature();
for (Actor a : nearbyActors) {
if (a instanceof Creature) {
mine = (Creature) a;
}
}
return mine;
}
问题
如您所见,getNextXXXXX()方法非常相似,只返回不同的对象,逻辑相同,如何干? actOnXXXX()似乎也属于DRY类别,但它们大致相同,对不同的对象使用相同的逻辑。怎么解决这个问题?
答案 0 :(得分:9)
让它接受一个classtype:
private <T> T getNext(Class<T> type) {
for (Actor a : getActors()) {
if (type.isAssignableFrom(a.getClass())) {
return (T) a;
}
}
return null; //or type.newInstance(); if you want a guaranteed object, but this restricts your constructor.
}
或者使用Java 8:
private <T> T getNext(Class<T> type) {
return (T) getActors().stream()
.filter(a -> type.isAssignableFrom(a.getClass()))
.findFirst().orElse(null);
}
但用法是一样的:
Monster next = getNext(Monster.class);
打破这个问题,你知道两类事情:
你需要什么:
t
类型的下一个对象。t
的方法
输入你有什么:
t
t
类型此外,所有这些方法之间的唯一差异是一回事:它是哪种类型。所以我们确实“将它变成一个变量”,因此它变成了一个方法参数。
打破这种局面我们只需要以完成此任务的方式组织代码:
method: //receives a "type" as a parameter
iterate the list of possible `t`s //our list of objects
if some_t == type //our comparison, previously `a instanceof Type`
return some_t //our result is found
return null //or a new object, but essentially our "default"
这里唯一的主要区别是:
some_t instanceof Type
type.isAssignableFrom(some_t.getClass())
醇>
原因在于,这只是您在使用Class<T>
通过反射动态制作对象会限制您的选项并具有处理异常。返回null
或空Optional<T>
有助于表示您没有结果,并且来电者可以采取相应行动。您也可能只是传递默认对象本身,然后返回instanceof
检查。
问自己同样的假设“我需要什么,我能提供什么/有什么”,这将有助于你将问题分解为更小的步骤,并解决更大的难题。
答案 1 :(得分:1)
我认为,您的代码和逻辑存在混淆。 举个例子,如果你需要迭代列表,你不需要创建一个新对象。也就是说,在下面的代码片段中,“new Monster()”不需要编写
Monster mine = null; // new Monster();
for (Actor a : nearbyActors) {
if (a instanceof Monster) {
mine = (Monster) a;
}
}
无论如何,答案是“Java中的类型推断”。 https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html
您的问题的答案是
package __TypeInference;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
new Main().doLogic();
}
private void doLogic() {
List<Actor> nearbyActors = getActors();
for (Actor actor : nearbyActors) {
// do with the next actor
System.out.println(actor.toString());
}
}
private List<Actor> getActors() {
List<Actor> actors = new ArrayList<Actor>();
actors.add(new Monster());
actors.add(new Creature());
actors.add(new Monster());
actors.add(new Creature());
return actors;
}
class Monster extends Actor {
@Override
public String toString() {
return "Monster";
}
}
class Creature extends Actor {
@Override
public String toString() {
return "Creatue";
}
}
class Actor {
}
}
答案 2 :(得分:1)
我认为你想要的是将getNextMonster
和getNextCreature
结合起来,因为它们重复了代码。
这里最好的办法是编写一个执行此操作的通用方法:
private <T extends Actor> T getNextActor(T newActor) {
ArrayList<Actor> nearbyActors = getActors();
T mine = newActor;
for (Actor a : nearbyActors) {
if (a instanceof T) {
mine = (T) a;
}
}
return mine;
}
你可以这样称呼它:
// This is equivalent to calling getNextCreature()
getNextActor(new Creature());
// This is equivalent to calling getNextMonster()
getNextActor(new Monster());
让我解释一下代码。
新方法返回Actor
类型。你通过传递参数告诉它你想要什么样的演员。该参数是必要的,因为您不能像这样初始化泛型类型参数:
new T();
因为无参数构造函数可能不可用。这就是调用者的工作。
我真的不知道我在说什么......
该方法具有以下优点:
getNextXXX
的方法(其中XXX
是Actor
的子类)时,您不需要。只需致电getNextActor(new XXX())
!getNextXXX
的实现,您只需更改一个方法而不是2。