如何使用Java Generics强制执行类型限制

时间:2017-11-06 00:39:41

标签: java algorithm generics design-patterns

这个问题有点先进,所以自然也有点复杂。我会尽力做到尽可能清楚。

正如标题所示,我想在从一些顶层(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");
    }
}

如果您还没有注意到,但在这里我正在利用策略模式,我将不同的算法通过静态不变代码的接口隔离到一个系列中。

编辑:我想维护此处使用的策略模式。

2 个答案:

答案 0 :(得分:1)

首先输入&#34;变量&#34;进入Engine的正式parmae​​ter列表:

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!");
    }
}