责任链模式 - 与后代的紧密耦合

时间:2013-07-31 20:45:17

标签: java oop

我遇到了如何将操作放入链中的问题,并且可以在处理操作期间传递其他参数。

让我们考虑简单的流程链。输入是表示图像的对象。 调整第一张图像的大小,然后将其部署到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和path。 我不能每次创建和关闭连接,因此代码必须传播:

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 个答案:

答案 0 :(得分:2)

我认为在你的情况下最强大的解决方案就是添加某种处理上下文。

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

通过这种方式,您可以灵活地添加新参数,而无需更改ImageProcessor的签名并保持实现者彼此分离。

类似的东西的真实例子是Java EE中的request \ session \ servlet上下文。您可以在各种生命周期阶段将内容放入其中(例如,关于哪些URL应该要求auth的安全配置选项)然后在需要时获取此内容(例如在Filter中阻止\允许基于身份验证要求访问资源)。

<强>更新

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

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

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

    // ...

}

因此,上下文是一个常见的地方,有助于向特定处理器提供数据,抽象出有关此数据的详细信息,从而将特定处理器彼此分离。

答案 1 :(得分: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();

答案 2 :(得分: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,你需要在循环中分离一些东西。

答案 3 :(得分:0)

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

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