2

我遇到了问题,如何将动作放入一个链中,并有可能在处理动作期间传递额外的参数。

让我们考虑一个简单的流程链。输入是表示图像的对象。调整第一个图像的大小,然后部署到 ftp 并保存到 db。使用责任链模式,调用可能如下所示:

ImageProcessor p = new ImageResizer(desiredSize);
p.setNext(new (new ImageDeployer(ftpServer, path)));
p.setNext(new (new ImageDbSaver(dbConnection, table)));
p.process(image);
p.close();

这对于一个图像非常有效。我想循环处理图像并在那里设置desiredSize和路径。我无法每次都创建和关闭连接,因此必须传播代码:

ImageProcessor p = new ImageResizer();
p.setNext(new (new ImageDeployer(ftpServer)));
p.setNext(new (new ImageDbSaver(dbConnection, table)));

for(Image image : images) {
  p.process(image, size, path);
}
p.close();

解决方案的一个问题是 ImageProcessor 不应该知道大小和路径。如果只使用 ImageDbSaver 参数,如大小和路径,则没有意义。
有什么更好的方法呢?

4

4 回答 4

2

我想在您的情况下最强大的解决方案是添加某种处理上下文。

在最简单的情况下,您可以(1)使用,例如Map<String, Object>,(2)使用特定于各种处理器的参数打包它,(3)将其传递给p.process(...)并(4)然后提取,例如size在调整图像大小的处理器中.

这样,您将获得添加新参数的灵活性,而无需更改签名ImageProcessor并保持实现者彼此分离。

Java EE 中的 request\session\servlet 上下文就是类似的真实世界示例。您可以在各个生命周期阶段将内容放入其中(例如,有关哪些 url 应该需要身份验证的安全配置选项),然后在需要的地方获取这些内容(例如,在过滤器中根据身份验证要求阻止\允许访问资源)。

更新

使用代码示例更新答案以演示该想法。

因此,在您的代码中的某处,您可以在其中构建处理器链:

ImageProcessor p = new ImageResizer(desiredSize);
p.setNext(new (new ImageDeployer(ftpServer, path)));
p.setNext(new (new ImageDbSaver(dbConnection, table)));

在(可能)其他地方,您创建和配置您的处理上下文(实际上并不需要在一个地方配置所有处理器):

Map<String, Object> context = new HashMap<String, Object>();
context.put("image_width", new Integer(640));

在代码的另一个地方,您进行处理,将上下文传递给它(我为所有处理重用上下文,但您可能对每个图像使用不同的上下文):

for(Image image : images) {
  p.process(image, context);
}
p.close();

现在,在你的某个地方ImageResizer

@Override
void process(Image image, Map<String, Object> context) {

    // ...

    Integer imageWidth = (Integer) context.get("image_width");

    // ...

}

因此,上下文是一个常见的地方,它有助于将数据传递给特定的处理器,抽象出关于这些数据的细节,从而将特定的处理器彼此解耦。

于 2013-07-31T21:16:57.153 回答
1

您可以简单地将所有处理器存储到变量中,然后将它们链接起来。

ImageResizer resizer = new ImageResizer();
ImageDeployer deployer = new ImageDeployer(ftpServer);
ImageDbSaver saver = new ImageDbSaver(dbConnection, table);

resizer.setNext(deployer).setNext(saver);

for(Image image : images) {
    deployer.setPath(somePath);
    resizer.setDesiredSize(desiredSize);
    resizer.process(image);
}

resizer.close();
于 2013-08-01T08:15:35.237 回答
0

解决它的一种简单方法是在循环之外构造不变量。例如:

ImageDeployer deployer = new ImageDeployer(ftpServer);
ImageDbSaver dbSaver = new ImageDbSaver(dbConnection, );

for(Image image : images) {
  ImageProcessor p = new ImageResizer(desiredSize);
  p.setNext(deployer);
  p.setNext(dbSaver);
  p.process(image);
}
dbSaver.close();
deployer.close();

如果 ImageResizer 需要关闭,您将需要某种方法来分离循环中的内容。

于 2013-07-31T21:30:30.350 回答
0

如果性能不是问题,您将如何编码?我认为为每个图像构建一个自定义处理器链将是一个很好的解决方案,因为您似乎对每个图像都有不同的值。

现在,如果事实证明这太慢了(这肯定会发生),为什么不将一个DatabaseConnectionFtpConnection对象(在循环外初始化)传递给需要这些的处理器呢?

于 2013-08-01T08:52:50.330 回答