这个问题有点先进,所以自然也有点复杂。我会尽力做到尽可能清楚。
正如标题所示,我想在从一些顶层(main)构造对象时使用Java Generics来强制执行类型限制。
我从未真正使用过Java泛型,但我找到了一个非常好的用例,我不知道如何实现。
我想在编写对象时强制执行类型限制。让我试着用一个例子来澄清:
我有一个顶级的主要方法,我在这里唤起一个NumberEngine对象,我在其中初始化并调用它的方法。请注意,当我调用setExecuteBehavior()时,我将它传递给RunNumberEvaluation类型的对象(它与RunStringEvaluation一起实现了一个名为ExecutionBehavior的接口)。
顾名思义,NumberEngine只适用于Numbers而不适用于字符串,因此我不适合将setExecuteBehavior()传递给RunStringEvaluation类型的对象。如何在编译时强制执行此行为?
public static void main(String[] args) {
NumberEngine numberEngine = new NumberEngine();
numberEngine.init("/path/to/forms");
numberEngine.getEngineVesion();
numberEngine.setExecuteBehavior(new RunNumberEvaluation);
numberEngine.performExecution();
// Here this should not compile, essentially throw me a compile error saying it can only accept
// an object of type RunNumberEvaluation, sincle NumberEngine can only run
// objects of type RunNumberEvaluation, etc...
numberEngine.setExecuteBehavior(new RunStringEvaluation());
numberEngine.performExecution();
}
所以在这里我想基本上让NumberEngine的setExecuteBehavior只接受与数据相关的行为,就像处理与数字有关的数据而不是字符串。反之亦然StringEngine。我希望StringEngine只接受与Strings有关的对象而不是Numbers。
如何使用Java泛型实现此目的?
我在考虑这样的事情......
NumberEngine<? extends Numbers> extends Engine
甚至不确定这是否有意义......
我在下面列出了工作代码,以说明我正在尝试沟通的内容。
我有一个Engine类型的对象,它是一个抽象类,有许多扩展的具体类,如StringEngine,NumberEngine等等。我已将算法功能解耦为具有实现该接口的类的接口。
基础抽象类
public abstract class Engine {
ExecuteBehavior executeBehavior;
public void setExecuteBehavior(ExecuteBehavior executeBehavior) {
this.executeBehavior = executeBehavior;
}
public void performExecution() {
executeBehavior.execute();
}
public abstract void init(String pathToResources);
}
具体实施1级
public class StringEngine extends Engine {
public StringEngine() {
executeBehavior = new RunNumberEvaluation();
}
@Override
public void init(String pathToResources) {
System.out.println("Initializing StringEngine with resources "+pathToResources);
System.out.println("Successfully initialized StringEngine!");
}
}
具体实施2级
public class NumberEngine extends Engine {
public NumberEngine() {
executeBehavior = new RunStringEvaluation();
}
@Override
public void init(String pathToResources) {
System.out.println("Initializing NumberEngine with resources "+pathToResources);
System.out.println("Successfully initialized NumberEngine!");
}
}
算法界面
public interface ExecuteBehavior {
void execute();
}
算法实施1
public class RunNumberEvaluation implements ExecuteBehavior {
@Override
public void execute() {
// some processing
System.out.println("Running numeric evaluation");
}
}
算法实施2
public class RunStringEvaluation implements ExecuteBehavior {
@Override
public void execute() {
// some processing
System.out.println("Running string evaluation");
}
}
如果您还没有注意到,但在这里我正在利用策略模式,我将不同的算法通过静态不变代码的接口隔离到一个系列中。
编辑:我想维护此处使用的策略模式。
答案 0 :(得分:1)
首先输入&#34;变量&#34;进入Engine的正式parmaeter列表:
public abstract class Engine<B extends ExecuteBehavior> {
B executeBehavior;
public void setExecuteBehavior(B executeBehavior) {
this.executeBehavior = executeBehavior;
}
public void performExecution() {
executeBehavior.execute();
}
public abstract void init(String pathToResources);
}
然后您可以按照自己的方式定义子类:
public class StringEngine extends Engine<RunStringEvaluation> {
public StringEngine() {
executeBehavior = new RunStringEvaluation();
}
@Override
public void init(String pathToResources) {
System.out.println("Initializing StringEngine with resources "+pathToResources);
System.out.println("Successfully initialized StringEngine!");
}
}
在您提供的示例代码中,您不需要。只需将setExecuteBehavior
移到子类并将其设为私有。
答案 1 :(得分:1)
使用泛型实现这一点非常简单,你完全正确地尝试使用泛型
你所要做的就是像这样改变你的课程
首先是界面
public interface ExecuteBehavior<T> {
void execute();
}
然后是抽象实现
public abstract class Engine<T> {
ExecuteBehavior<T> executeBehavior;
public void setExecuteBehavior(ExecuteBehavior<T> executeBehavior) {
this.executeBehavior = executeBehavior;
}
public void performExecution() {
executeBehavior.execute();
}
public abstract void init(String pathToResources);
}
最后是RunNumberEngine和NumberEngine
public class RunNumberEvaluation implements ExecuteBehavior<Number> {
@Override
public void execute() {
// some processing
System.out.println("Running numeric evaluation");
}
}
NumberEngine
public class NumberEngine extends Engine<Number> {
public NumberEngine() {
executeBehavior = new RunNumberEvaluation();
}
@Override
public void init(String pathToResources) {
System.out.println("Initializing NumberEngine with resources "+pathToResources);
System.out.println("Successfully initialized NumberEngine!");
}
}
RunStringEngine,后跟StringEngine
public class RunStringEvaluation implements ExecuteBehavior<String> {
@Override
public void execute() {
// some processing
System.out.println("Running string evaluation");
}
}
StringEngine
public class StringEngine extends Engine<String> {
public StringEngine() {
executeBehavior = new RunStringEvaluation();
}
@Override
public void init(String pathToResources) {
System.out.println("Initializing StringEngine with resources "+pathToResources);
System.out.println("Successfully initialized StringEngine!");
}
}