是否有一种模式可以使用不同数量的输入/输出,但工作的核心职责相同?

我的代码库中有一个模式看起来很像这样:我们正在处理来自队列的消息,然后将该消息传递到下一个队列。到目前为止,用例是我们处理并产生相同类型的消息。

public interface Processor<T> {
  T process(T thing);
}

该用例已演变为处理和产生不同类型的用例。另外,我们可能需要处理一种类型并产生一系列其他类型。

类似:

public interface NewProcessor<I,O> {
  O process(I thing;)
}

,将来可能会需要类似的东西

public interface FutureProcessor<I,O1,O2> { //potentially N number of O
  Pair<O1,O2> process(I thing);
}

我的问题是:除了拥有三个单独的类之外,还有一种表达这种清洁剂的方法吗?我在这里可以使用一个很好的已知层次结构吗?

我们有第一类处理器的抽象用户,我希望不必在每次添加新处理器时都进行重写。今天它是这样的:

public abstract AbstractModule<T> {
  private Processor<T> processor;
  public AbstractModule(Processor<T> processor) {
   this.processor = processor;
  }

  T runmodule(T input) {
    // abstract validateInput(input);
    T result = processor.process();
    // record results
    return result;
  }
}

任何有关如何执行此操作的已知模式或建议,将不胜感激!

st86591985 回答:是否有一种模式可以使用不同数量的输入/输出,但工作的核心职责相同?

您的用例是获取一个对象,对其进行处理并生成一个新对象。基本上是一个参数的函数。我认为关键部分是参数的数量,因为您只能在Java中返回一个结果。如果您确定将来不再需要一次处理多个对象,那么就没有比使用已经定义的函数更通用的方法了(我会在JDK中使用不过,在这种情况下,FunctionUnaryOperator)是可能的。

假设您要继续使用自定义函数,并且不想像您所说的那样更改AbstractModule。我至少将Processor重命名为UnaryProcessor。然后,我将其更改如下:

public interface Processor<T,R> {
    R process(T t);
}

public interface UnaryProcessor<T> extends Processor<T,T> {}

这时,您将能够处理您提到的Processor<T,Pair<O1,O2>>的上一个用例。相同的逻辑适用于任何将来的用例,您只需要用当时需要的任何类型(例如List<E>)来替换返回类型。

,

与其从方法调用中返回结果,不如对每个处理器可能从输入生成的结果进行回调,以初始化每个处理器。

这非常适合队列处理应用程序,因为回调可能会为其他队列生成一条新消息,并且您可以轻松拦截结果以执行诸如监视之类的事情,而无需修改处理器。

interface Processor<T> {
  void process(T message);
}

interface Output<T> {
  result(T result);
}

class SomeKindOfProcessor implements Processor<SomeInput> {

  private final Output<? super Foo> foo;
  private final Output<? super Bar> bar;

  // These parameters are probably injected by some sort of IoC container.
  // They are easy to mock in tests too,so you can unit test this
  // class in isolation.
  SomeKindOfProcessor(Output<? super Foo> foo,Output<? super Bar> bar) {
    this.foo = foo;
    this.bar = bar;
  }

  @Override
  public void process(SomeInput input) {
     /* Do some work that results in a Bar instance */
     bar.result(new Bar(...));
     /* Do some more work that might result in a Foo instance. */
     if (...) {
        foo.result(new Foo(...));
     }
  }

}

如果回调实现需要将结果与输入相关联,则通常可以使用输入中的一些标识符来实现。

,

您的输出结果可能是抽象的,您总是将其返回

class Result<T1,T2,T3>{// only change Result class   
    boolean hasType1     //no need to change method interface that returns Result
    boolean hasType2
    boolean hasType3

    T1 t1
    T2 t2
    T3 t3    
    // you can use other implementation such as array...
}

public interface Processor<T> {//only one interface that always returns Result
  Result process(T thing);
}
,

您不必保持处理器功能接口采用多个输入和/或输出,而是将其保持不变,而是使用汇总的输入和/或输出。

您应该优先为集合命名一个有用的名称,因为一对整数可能例如根据这些int表示什么而称为Vertex,Point,Dimension等。仅当您的聚合没有有用的名称并且您不打算在其他地方使用它时,才可以使用诸如ProcessInput或ProcessOutput之类的通用名称。

agreget示例:

class Vertex {
   final public int x;
   final public int y;

   public Vertex(int x,int y) {
      this.x = x;
      this.y = y;
   }
}

我通常更喜欢将字段保留在这样一个汇总的final中,以使时间不变,但是没有什么要求您这么做。

就像其他建议的那样,可以创建通用聚合。不要以为您需要这样做。我通常更喜欢带有上帝有用名称的聚合,并且其中单个成员字段或属性也可以具有良好的有用名称。必须记住,第三个整数是计数,第二个String是名称,这可能导致代码不那么容易阅读。

,

也许您可以应用装饰器模式之类的东西。这将使您拥有一个界面,例如java.util.Function,但可以轻松地为输入和输出引入中间转换步骤。

class Decorator<I,O,D> implements Function<I,D>
{
    private final Function<I,O> function;
    private final Function<O,D> delegate;

    public Decorator( Function<I,O> function,Function<O,D> delegate )
    {
        this.function = function;
        this.delegate = delegate;
    }

    @Override
    public D apply( I input )
    {
        O output = function.apply( input );
        return delegate.apply( output );
    }
}

这是一个简单的示例,将字符串转换为整数,修改字符串,然后转换回整数:

@Test
public void testDelegate()
{
    Function<Integer,String> intToString = String::valueOf;

    Decorator<Integer,String,String> repeatString = new Decorator<>(
            intToString,s -> s + s );

    assertEquals( "33",repeatString.apply( 3 ));

    Decorator<Integer,Integer> repeatThenToInt = new Decorator<>(
            repeatString,Integer::valueOf );

    assertEquals( 33,repeatThenToInt.apply( 3 ).intValue() );
}
本文链接:https://www.f2er.com/2423697.html

大家都在问