如何应用 Composition 在 Struts2 Action 类之间共享代码
如果您使用继承并将所有公共代码和属性放入基类中,则在 Action 类之间共享代码很容易。作为最佳实践,我认为经验法则是优先选择组合而不是继承。不过,我发现将这个概念应用到 Action 类中非常困难。也许我做得不对。
例如,我有 3 个不同的 Action 类。它们都处理用户注册的不同方式(用户可以从多个表单进行注册)它们最终都调用相同的服务方法,并且需要以相同的方式处理错误。常见的代码类似于:
public class RegisterAction1 {
public String execute() {
...Leaving out code here....
try {
registrationService.register(user);
} catch (BusinessException e) {
if(e.getErrors().containsKey("someError3)){
return "Case1";
}
else if (e.getErrors().containsKey("someError1")) {
session.put(Constants.SESSION_REGISTERVO, registerVO);
return "Case2";
} else if(e.getErrors().containsKey("someError2")) {
this.addFieldError("aliasName", this.getText("some.error"));
} else if(ce.getErrors().containsKey("someError3")) {
this.someFieldThatMustBeSetForView1 = true;
this.someFieldThatMustBeSetForView2 = true;
this.addFieldError("addressLine1", null);
this.addFieldError("addressLine2", null);
this.addFieldError("city", null);
}
}
...Leaving out code here....
return "Success";
}
}
要使用组合,我认为您可以将这段逻辑移至“Helper”类中,并在 Action 类中引用该 Helper。如果您要在这个帮助程序类中创建一个实现此公共代码的“callService”方法,您将如何处理许多代码实际上正在修改类上的字段的事实......即,您是否传递对辅助方法的操作如下所示?如果是这样,您如何处理它可能是三个不同操作类之一(即 RegisterAction1、RegisterAction2、RegisterAction3)的事实?
public String callService(RegisterAction1 registerAction) {
Sharing code between Action classes is easy if you use Inheritance and put all the common code and properties into a Base class. As a best practice, I think the rule of thumb is to prefer composition over inheritance. I'm finding it extremely hard to apply this concept to Action classes, though. Perhaps I'm not doing it right.
For instance, I have 3 different Action classes. They all handle different ways a user may register (A user can register from more than 1 form) They all ultimately call the same service method and need to handle the errors the same way. The common code would like something like:
public class RegisterAction1 {
public String execute() {
...Leaving out code here....
try {
registrationService.register(user);
} catch (BusinessException e) {
if(e.getErrors().containsKey("someError3)){
return "Case1";
}
else if (e.getErrors().containsKey("someError1")) {
session.put(Constants.SESSION_REGISTERVO, registerVO);
return "Case2";
} else if(e.getErrors().containsKey("someError2")) {
this.addFieldError("aliasName", this.getText("some.error"));
} else if(ce.getErrors().containsKey("someError3")) {
this.someFieldThatMustBeSetForView1 = true;
this.someFieldThatMustBeSetForView2 = true;
this.addFieldError("addressLine1", null);
this.addFieldError("addressLine2", null);
this.addFieldError("city", null);
}
}
...Leaving out code here....
return "Success";
}
}
To use composition I would think that you would move this piece of logic into a "Helper" class and have a reference to that Helper in the Action class. If you were to create a "callService" method in this helper class which implemented this common code, how would you handle the fact that a lot of the code is actually modifying fields on the class ... i.e., do you pass a reference to the Action to the helper method like the following? And if so, how do you handle the fact that it could be 1 of three different action classes (i.e., RegisterAction1, RegisterAction2, RegisterAction3)?
public String callService(RegisterAction1 registerAction) {
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
有多种方法可以做到这一点。
不过,如果有非操作类需要修改操作数据,我可能会选择 ModelDriven 方法,并传递模型,将其与 S2 架构解耦(假设您的操作扩展了 <代码>操作支持)。
在您的情况下,您还可以直接修改字段错误(这只是一张地图)。天真的(可能足够好)方法是要么直接传递它,要么传递回一些可用于修改字段错误的东西,无论是在拦截器中,还是在基本操作类方法。或者,如下面的选项所示,假设访问
ValidationAware
impl(以及模型或ModelDriven
impl)。另一种选择是将相关部分封装在接口中,因此传递给帮助器的唯一内容是接口实现。如果您想直接访问字段错误映射,这还可以包括 ValidationAware。
这两种解决方案还解决了“不同类型的注册操作”问题,除非它们有很大不同。如果是的话,我会考虑保持原样——不必要地过度设计某些东西是没有意义的。
There's a number of ways this could be done.
If there are non-action classes that need to modify action data, though, I might opt for a
ModelDriven
approach, and have the model passed around, decoupling it from the S2 architecture (assuming your actions extendActionSupport
).In your case you're also directly modifying field errors (which is just a map). The naive (and probably good-enough) approach would be to either just pass that along as well, or pass back something that can be used to modify the field errors, either in an interceptor, or in a base action class method. Or, as in the option below, assume access to a
ValidationAware
impl (as well as either a model, or aModelDriven
impl).Another option would be to encapsulate the relevant portions in an interface, so the only thing passed to the helper is an interface implementation. This could also include
ValidationAware
if you wanted direct access to the field errors map.Both of those solutions also address the "different type of registration actions" issue, unless they're wildly different. If they are, I'd consider just keeping things as-is--there's no point in needlessly over-engineering something.