views:

85

answers:

3

I have to work with some code that isn't truly MVC (i.e., it doesn't use an explicit framework among other things). Right now we make do with servlets that pass data to services.

Here is my problem. I am receiving a post to a servlet that contains a whole bunch of address data that I have to save to the database. The data is (obviously) in the HttpServletRequest object. My question is, how do I pass this data into a service? I am reluctant to do it like this:

AddressService.saveAddress(request);

Because I don't think the service should have a dependency on the request. My other option is to do something like this:

String addressLine = request.getParameter("addressLine");
..
.. about 7 other parameters
..
String zip = request.getParameter("zip");

AddressService.saveAddress(addressLine, ... 7 other parameters ..., zip);

But I don't like having a function with a huge number of parameters either. I was thinking of making an intermediate object called AddressData that would hold data from the request, and then passing that into the service. Is that an acceptable way of doing things?

+2  A: 

Yes, it is a known way of eliminating this dependency. I can't recall exact sources out of the top of my head, but several books include this technique.

A variation of this would be to make AddressData a wrapper, which instead of copying and holding all the needed request data in itself, just keeps a private reference to it and forwards all calls to it. This may be more flexible and cleaner, especially if there are many request parameters and/or parameters are changed / new ones are introduced frequently.

Péter Török
+2  A: 

Yes this is a valid solution and is called a Parameter Object.

Finglas
+1  A: 

Use interfaces to decouple:

Model:

public interface Address {
    String getLine1();
    String getLine2();
    ...
    String getZip();
}
public class AddressBase implements Address {
    public AddressBase(String line1, String line2, ..., String zip) {
       ...
    }
    ...
}
public class AddressService {
    void saveAddress(Address address);
}

Now the controller(s) has options and the model is protected from the controller implementation:

Controller Option 1:

// wrap - lazy interrogator
class AddressRequestWrapper implements Address {
    ...
    AddressRequestWrapper(HttpRequest request) {
        this.request = request;
    }
    String getLine1() {   return request.get(LINE_1_FIELD_ID); }
    ...
}

Controller Option 2:

// "wrap" - eager interrogator
class AddressRequestWrapper extends AddressBase {
    AddressRequestWrapper(HttpRequest request) {
        super(
            request.get(LINE_1_FIELD_ID),
            request.get(LINE_2_FIELD_ID),
            ...
            request.get(ZIP_FIELD_ID)
        );
  }
  ...
}

Controller Option 3:

// Just use AddressBase directly
Address address =
    new AddressBase(
            request.get(LINE_1_FIELD_ID),
            request.get(LINE_2_FIELD_ID),
            ...
            request.get(ZIP_FIELD_ID)
    );
AddressService.saveAddress(address);
Bert F