首页 / JAVA / 如何使用Java泛型编写管道类
如何使用Java泛型编写管道类
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了如何使用Java泛型编写管道类,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含7505字,纯文字阅读大概需要11分钟。
内容图文
![如何使用Java泛型编写管道类](/upload/InfoBanner/zyjiaocheng/686/5f9c0a0a630f4c01ac461a785e929c60.jpg)
以下类声明用于处理数据项的管道.目前,这可以正常工作.但是在Pipeline类中有一些我不知道要正确解决的警告:
public abstract class Stage<In, Out> {
public abstract DataItem<Out> processItem(DataItem<In> data) throws Exception;
}
public class DataItem<T> {
public T data;
public DataItem(T obj) {
this.data = obj;
}
}
// chain Stages together
public class Pipeline {
private List<Stage<?,?>> stages;
public Pipeline(List<Stage<?,?>> stages) {
this.stages = stages;
}
// WARNING HERE: DataItem is a raw type. References to generic type should be parameterized
public void processItem(DataItem dataItem) throws Exception {
for (Stage<?, ?> stage: stages) {
// WARNING HERE: DataItem is a raw type. References to generic type should be parameterized
dataItem = stage.processItem(dataItem);
}
}
我尝试通过添加通配符来更改processItem()声明,但这会导致编译错误:
public void processItem(DataItem<?> dataItem) throws Exception {
for (Stage<?, ?> stage: stages) {
// COMPILATION ERROR: The method processItem(DataItem<capture#2-of ?>)
// in the type Stage<capture#2-of ?,capture#3-of ?> is not applicable
// for the arguments (DataItem<capture#4-of ?>)
dataItem = stage.processItem(dataItem);
}
}
有针对这个的解决方法吗 ?
解决方法:
首先,警告仅源于管道本身不是通用的事实.它不携带任何有关其预期作为初始输入的信息.
我对解决此问题的建议涉及其他一些概括和改进(我认为是改进):
>让舞台成为界面.当您有一个仅包含抽象方法的抽象类时,则通常应为一个接口.当实现者可以等效地扩展其Base实现实现阶段时,无需将实现者固定到特定的扩展阶段.
>不要低估第一点.它使您可以说Pipeline实现了Stage.考虑一下这为用户带来的力量.他们可以在管道中组装复杂的流程,然后在更复杂的流程中简单地将此管道用作一个阶段.从本质上讲,这是Flow-Based Programming的核心概念之一!
>为管道对象创建类型安全的构建器.
最后一点是您最初的问题是什么.那么,此构建器类中最重要的方法就是:
public <NextOut> PipelineBuilder<In, NextOut> add(Stage<Out, NextOut> stage)
{
stages.add(stage);
// This cast is safe as per construction of the pipeline
@SuppressWarnings("unchecked")
PipelineBuilder<In, NextOut> result =
(PipelineBuilder<In, NextOut>) this;
return result;
}
这个想法是,只要您有管道< S,T>的构建器,并附加具有类型< T,U>的阶段,构建器就会变成具有< S,U>类型的构建器. .
(如您所见,它包含一个未经检查的演员表,但是根据构建器和以后使用构建器以及管道的使用情况,该演员表是安全的)
这些过渡可以用过于复杂的形式编写:
private static void showTypeTransitions()
{
Stage<String, String[]> s0 = null;
Stage<String[], List<Integer>> s1 = null;
Stage<List<Integer>, Integer> s2 = null;
// Starting with a builder for a Pipeline<String, String[]>
PipelineBuilder<String, String[]> b0 = PipelineBuilder.create(s0);
// Appending a Stage<String[], List<Integer>> turns it
// into a builder for a Pipeline<String, List<Integer>>
PipelineBuilder<String, List<Integer>> b1 = b0.add(s1);
// Appending a Stage<List<Integer>, Integer> turns it
// into a builder for a Pipeline<String, Integer>
PipelineBuilder<String, Integer> b2 = b1.add(s2);
// Finally, build it
Pipeline<String, Integer> pipeline = b2.build();
}
但这不是必需的.建造者的意图是使建筑具有流畅的界面:
Pipeline<String, Integer> pipeline = PipelineBuilder
.create(splitter)
.add(transformer)
.add(accumulator)
.build();
(请注意,您还可以省略Builder,并向Pipeline类添加类似的方法.但这需要对构造函数进行一些调整,等等).
这是显示此方法的MCVE.在showBasicUsage方法中,显示了基本用法(因此命名为…).在showHowNiceItIsToUseAnInterface方法中,在基本示例中创建的管道用作创建的新管道的一个阶段.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
interface Stage<In, Out>
{
DataItem<Out> processItem(DataItem<In> data) throws Exception;
}
class DataItem<T>
{
public T data;
public DataItem(T obj)
{
this.data = obj;
}
}
class Pipeline<In, Out> implements Stage<In, Out>
{
private List<Stage<?, ?>> stages;
Pipeline(List<Stage<?, ?>> stages)
{
this.stages = stages;
}
@Override
public DataItem<Out> processItem(DataItem<In> dataItem) throws Exception
{
DataItem<?> current = dataItem;
for (Stage<?, ?> stage : stages)
{
current = apply(stage, current);
}
// This cast is safe as per construction of the pipeline
@SuppressWarnings("unchecked")
DataItem<Out> result = (DataItem<Out>) current;
return result;
}
private <I, O> DataItem<O> apply(
Stage<I, O> stage, DataItem<?> dataItem) throws Exception
{
// This cast is safe as per construction of the pipeline
@SuppressWarnings("unchecked")
DataItem<I> typedDataItem = (DataItem<I>)dataItem;
DataItem<O> result = stage.processItem(typedDataItem);
return result;
}
}
class PipelineBuilder<In, Out>
{
private List<Stage<?, ?>> stages;
static <In, Out> PipelineBuilder<In, Out> create(Stage<In, Out> stage)
{
PipelineBuilder<In, Out> pipelineBuilder =
new PipelineBuilder<In, Out>(stage);
return pipelineBuilder;
}
private PipelineBuilder(Stage<In, Out> stage)
{
stages = new ArrayList<Stage<?,?>>();
stages.add(stage);
}
public <NextOut> PipelineBuilder<In, NextOut> add(Stage<Out, NextOut> stage)
{
stages.add(stage);
// This cast is safe as per construction of the pipeline
@SuppressWarnings("unchecked")
PipelineBuilder<In, NextOut> result =
(PipelineBuilder<In, NextOut>) this;
return result;
}
public Pipeline<In, Out> build()
{
return new Pipeline<In, Out>(stages);
}
}
public class PipelineExample
{
public static void main(String[] args) throws Exception
{
showBasicUsage();
showHowNiceItIsToUseAnInterface();
}
private static void showBasicUsage() throws Exception
{
Pipeline<String, Integer> pipeline = createExamplePipeline();
DataItem<String> in = new DataItem<>("1 35 42 2 10 5 2 3");
DataItem<Integer> out = pipeline.processItem(in);
System.out.println(out.data); // prints 100
}
private static void showHowNiceItIsToUseAnInterface() throws Exception
{
Stage<List<Integer>, String> stringCreator =
dataItem -> new DataItem<>(
dataItem.data.stream()
.map(String::valueOf)
.collect(Collectors.joining(" ")));
// Create the whole pipeline that was used in the basic usage
// example, and use it as one stage in the new pipeline:
Stage<String, Integer> pipelineAsStage = createExamplePipeline();
Pipeline<List<Integer>, Integer> pipeline = PipelineBuilder
.create(stringCreator)
.add(pipelineAsStage)
.build();
DataItem<List<Integer>> in = new DataItem<>(Arrays.asList(0,1,2,3,4));
DataItem<Integer> out = pipeline.processItem(in);
System.out.println(out.data); // prints 10
}
private static Pipeline<String, Integer> createExamplePipeline()
{
Stage<String, String[]> splitter =
dataItem -> new DataItem<>(dataItem.data.split(" "));
Stage<String[], List<Integer>> transformer =
dataItem -> new DataItem<>(Arrays.stream(dataItem.data)
.map(Integer::parseInt)
.collect(Collectors.toList()));
Stage<List<Integer>, Integer> accumulator =
dataItem -> new DataItem<>(
dataItem.data.stream().reduce(0, Integer::sum));
Pipeline<String, Integer> pipeline = PipelineBuilder
.create(splitter)
.add(transformer)
.add(accumulator)
.build();
return pipeline;
}
private static void showTypeTransitions()
{
Stage<String, String[]> s0 = null;
Stage<String[], List<Integer>> s1 = null;
Stage<List<Integer>, Integer> s2 = null;
// Starting with a builder for a Pipeline<String, String[]>
PipelineBuilder<String, String[]> b0 = PipelineBuilder.create(s0);
// Appending a Stage<String[], List<Integer>> turns it
// into a builder for a Pipeline<String, List<Integer>>
PipelineBuilder<String, List<Integer>> b1 = b0.add(s1);
// Appending a Stage<List<Integer>, Integer> turns it
// into a builder for a Pipeline<String, Integer>
PipelineBuilder<String, Integer> b2 = b1.add(s2);
// Finally, build it
Pipeline<String, Integer> pipeline = b2.build();
}
}
(为了方便起见,这些阶段取自the answer from Kirill Simonov,因为它们是一个很好的示例用例)
内容总结
以上是互联网集市为您收集整理的如何使用Java泛型编写管道类全部内容,希望文章能够帮你解决如何使用Java泛型编写管道类所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。