1

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) {
Community
  • 1
  • 1
JasonStoltz
  • 3,040
  • 4
  • 27
  • 37

1 Answers1

2

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 extend ActionSupport).

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 a ModelDriven 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.

Dave Newton
  • 158,873
  • 26
  • 254
  • 302
  • Awesome, I think ModelDriven could REALLY help with some of the troubles I'm facing. In general, do you think sharing code via a Base action class is OK design? – JasonStoltz Sep 27 '11 at 11:48
  • 1
    Depends on what kind of code is being shared, I suppose. Sometimes I'll start off with a bunch of shared code in an action class and eventually move it out if it doesn't actually belong in the web layer. When it's web-layer, app-specific code, sure--I've never had an action hierarchy over ~2 layers deep. If it's *corporation*-specific code, I might rethink, but that usually ends up in a relatively fat base action class as well. – Dave Newton Sep 27 '11 at 12:26