在Java中,如何创建在每个实例中方法不同的类?

在Java中,如何创建在每个实例中方法不同的类?,java,class,methods,behavior-tree,Java,Class,Methods,Behavior Tree,我正在开发一个基本的游戏AI,我正在尝试使用一个名为Transition的抽象类将节点之间的转换封装在行为树中 现在,Transition如下所示: package com.game.behaviors; public abstract class Transition { public abstract Node getNextNode(); } @FunctionalInterface public interface Transition { public Node g

我正在开发一个基本的游戏AI,我正在尝试使用一个名为
Transition
的抽象类将节点之间的转换封装在行为树中

现在,
Transition
如下所示:

package com.game.behaviors;

public abstract class Transition {
    public abstract Node getNextNode();
}
@FunctionalInterface
public interface Transition {
    public Node getNextNode();
}
我希望能够在每个转换实例上指定getNextNode方法内部的逻辑。例如,某些转换将始终返回相同的
节点
,而其他转换可能基于随机数生成器或某些其他逻辑返回多个节点中的一个

我知道我可以通过为我想要的每个行为创建一个继承自
Transition
的类,然后获取这些类的实例来实现这一点,如下所示:

class RealTransition extends Transtition{
    Node thisNode = someNode;

    public Node getNextNode(){
        return thisNode;
    }
}

RealTransition rt = new RealTransition();
someObject.someMethodThatWantsATransition(rt);

作为一个主要在Javascript中工作的JavaNoob,这感觉很笨拙。创建一个新的类,我知道我只会实例化一次,这感觉应该是不必要的,特别是因为我可能会定义很多转换。有没有更好的方法来定义转换的工作方式?

Java最简洁的特性之一是能够使
枚举的每个值的行为不同。基本上,每个值都是从父级
enum
继承的单例对象。这听起来与你正在做的事情相匹配

有关详细信息,请参见中的常量特定方法。它从第740页的PDF开始

[编辑:从上面的链接复制的示例。当树的节点(例如,游戏中的角色类型)事先固定时,这是一种很好的模式。当应用于动态创建的对象时,它不起作用。]

//: enumerated/CarWash.java
import java.util.*;
import static net.mindview.util.Print.*;
public class CarWash {
 public enum Cycle {
 UNDERBODY {
 void action() { print("Spraying the underbody"); }
 },
 WHEELWASH {
 void action() { print("Washing the wheels"); }
 },
 PREWASH {
 void action() { print("Loosening the dirt"); }
 },
 BASIC {
 void action() { print("The basic wash"); }
 },
 HOTWAX {
 void action() { print("Applying hot wax"); }
 },
 RINSE {
 void action() { print("Rinsing"); }
 },
 BLOWDRY {
 void action() { print("Blowing dry"); }
 };
 abstract void action();
 }
 EnumSet<Cycle> cycles =
 EnumSet.of(Cycle.BASIC, Cycle.RINSE);
 public void add(Cycle cycle) { cycles.add(cycle); }
 public void washCar() {
 for(Cycle c : cycles)
 c.action();
 }
 public String toString() { return cycles.toString(); }
 public static void main(String[] args) {
 CarWash wash = new CarWash();
 print(wash);
 wash.washCar();
 // Order of addition is unimportant:
 wash.add(Cycle.BLOWDRY);
 wash.add(Cycle.BLOWDRY); // Duplicates ignored
 wash.add(Cycle.RINSE);
 wash.add(Cycle.HOTWAX);
 print(wash);
 wash.washCar();
 }
} /* Output:
/:枚举/CarWash.java
导入java.util.*;
导入静态net.mindview.util.Print.*;
公共级洗车{
公共枚举循环{
车底{
无效操作(){打印(“喷洒车身底部”);}
},
洗车{
void action(){print(“清洗车轮”);}
},
预洗{
void action(){print(“松开污垢”);}
},
基本的{
void action(){print(“基本清洗”);}
},
热蜡{
无效操作(){打印(“应用热蜡”);}
},
冲洗{
void action(){print(“Rinsing”);}
},
吹干{
无效操作(){打印(“吹干”);}
};
抽象无效行为();
}
枚举集循环=
枚举集(Cycle.BASIC、Cycle.RINSE);
公共无效添加(循环){cycles.add(循环);}
公共洗衣车(){
用于(循环c:循环)
c、 动作();
}
公共字符串toString(){return cycles.toString();}
公共静态void main(字符串[]args){
洗车=新洗车();
印刷(水洗);
wash.washCar();
//添加顺序不重要:
清洗。添加(循环。吹干);
wash.add(Cycle.BLOWDRY);//忽略重复项
清洗。添加(循环。冲洗);
清洗。添加(循环。热蜡);
印刷(水洗);
wash.washCar();
}
}/*输出:
[基本,冲洗] 基本洗涤 冲洗 [碱性、热蜡、冲洗、吹干] 基本洗涤 涂热蜡 冲洗 吹干
Java最简洁的特性之一是能够使
enum
的每个值表现不同。基本上,每个值都是从父级
enum
继承的单例对象。这听起来与你正在做的事情相匹配

有关详细信息,请参见中的常量特定方法。它从第740页的PDF开始

[编辑:从上面的链接复制的示例。当树的节点(例如,游戏中的角色类型)事先固定时,这是一种很好的模式。当应用于动态创建的对象时,它不起作用。]

//: enumerated/CarWash.java
import java.util.*;
import static net.mindview.util.Print.*;
public class CarWash {
 public enum Cycle {
 UNDERBODY {
 void action() { print("Spraying the underbody"); }
 },
 WHEELWASH {
 void action() { print("Washing the wheels"); }
 },
 PREWASH {
 void action() { print("Loosening the dirt"); }
 },
 BASIC {
 void action() { print("The basic wash"); }
 },
 HOTWAX {
 void action() { print("Applying hot wax"); }
 },
 RINSE {
 void action() { print("Rinsing"); }
 },
 BLOWDRY {
 void action() { print("Blowing dry"); }
 };
 abstract void action();
 }
 EnumSet<Cycle> cycles =
 EnumSet.of(Cycle.BASIC, Cycle.RINSE);
 public void add(Cycle cycle) { cycles.add(cycle); }
 public void washCar() {
 for(Cycle c : cycles)
 c.action();
 }
 public String toString() { return cycles.toString(); }
 public static void main(String[] args) {
 CarWash wash = new CarWash();
 print(wash);
 wash.washCar();
 // Order of addition is unimportant:
 wash.add(Cycle.BLOWDRY);
 wash.add(Cycle.BLOWDRY); // Duplicates ignored
 wash.add(Cycle.RINSE);
 wash.add(Cycle.HOTWAX);
 print(wash);
 wash.washCar();
 }
} /* Output:
/:枚举/CarWash.java
导入java.util.*;
导入静态net.mindview.util.Print.*;
公共级洗车{
公共枚举循环{
车底{
无效操作(){打印(“喷洒车身底部”);}
},
洗车{
void action(){print(“清洗车轮”);}
},
预洗{
void action(){print(“松开污垢”);}
},
基本的{
void action(){print(“基本清洗”);}
},
热蜡{
无效操作(){打印(“应用热蜡”);}
},
冲洗{
void action(){print(“Rinsing”);}
},
吹干{
无效操作(){打印(“吹干”);}
};
抽象无效行为();
}
枚举集循环=
枚举集(Cycle.BASIC、Cycle.RINSE);
公共无效添加(循环){cycles.add(循环);}
公共洗衣车(){
用于(循环c:循环)
c、 动作();
}
公共字符串toString(){return cycles.toString();}
公共静态void main(字符串[]args){
洗车=新洗车();
印刷(水洗);
wash.washCar();
//添加顺序不重要:
清洗。添加(循环。吹干);
wash.add(Cycle.BLOWDRY);//忽略重复项
清洗。添加(循环。冲洗);
清洗。添加(循环。热蜡);
印刷(水洗);
wash.washCar();
}
}/*输出:
[基本,冲洗] 基本洗涤 冲洗 [碱性、热蜡、冲洗、吹干] 基本洗涤 涂热蜡 冲洗 吹干
正如@ajb所述,您可以使用Java8中的函数接口做同样的事情。 这基本上是相同的,但是您使用匿名类来传递所需的行为

定义您的
转换
,如下所示:

package com.game.behaviors;

public abstract class Transition {
    public abstract Node getNextNode();
}
@FunctionalInterface
public interface Transition {
    public Node getNextNode();
}
然后在方法中使用lambda表达式:

someObject.someMethodThatWantsATransition(() -> {
    // your method body here;
});

由于任何函数接口只能有一个方法,因此会实例化一个新的
转换
,并调用它唯一的现有方法。

正如@ajb所述,您可以使用Java 8中的函数接口执行相同的操作。 这基本上是相同的,但是您使用匿名类来传递所需的行为

定义您的
转换
,如下所示:

package com.game.behaviors;

public abstract class Transition {
    public abstract Node getNextNode();
}
@FunctionalInterface
public interface Transition {
    public Node getNextNode();
}
然后在方法中使用lambda表达式:

someObject.someMethodThatWantsATransition(() -> {
    // your method body here;
});

由于任何函数接口只能有一个方法,因此会实例化一个新的
转换
,并调用它唯一的现有方法。

除了可以扩展基类之外,还可以在类中定义控制函数结果的属性,例如“int behavior”;在方法集中定义“if”(behavior==1)然后做点什么“如果(behavior==2)做点别的”这就是你在Java中是如何做的