One of the challenges we face with coding is dealing with coupling. Coupling is an important aspect of programming, it tells us how much our code is tangled. When coupling is too high, we can’t easily re-use code. When the coupling is too low it does little. You can measure coupling, there are several metrics for it even (for instance “Coupling between Objects, CBO”).
In this blog post I’d like to talk about a subtle introduction of coupling: when you introduce a factory method.
Consider you have an interesting piece of code, and this piece of code has quite a lot of properties:
class Person { private String firstName; private String lastName; // .. more properties here public void subcribeTo(Subscription subscription) { // do something interesting here } }
The problem is, because of the amount of properties and other dependencies, we’d like to simplify its creation by introducing a Factory method. In this case we are building a web application, so we take the Request as input to read the parameters:
class Person { private String firstName; private String lastName; // .. more properties here public static Person create(HttpServletRequest request, .. more arguments here .. ) { this.firstName = request.getParameter("firstName"); // .. read more properties // .. set up dependencies, etc. } public void subcribeTo(Subscription subscription) { // do something interesting here } }
In the code that uses Person, it becomes easier to construct the Person and we’re happy with that. However, we have introduced coupling on several levels:
- We construct the object with specific parameters in the create method. If we want to create from different parameters, we cannot use it. There is a coupling between the parameters and the properties.
- The object is constructed using a Request object. We cannot now move the class to an application that does not use the web. A person has nothing to do with a request, it is just convenience that we put the factory method in the Person class. There is a coupling between the code of Person and the dependency delivering the Request object.
There are several ways to deal with this. But lets start with the last reason of coupling. It is easy to fix this coupling by creating a Factory class within your web application. From there you can generate the Person object out of a request. The Person class has no create method anymore, and thus is not tightly coupled to a Request class. The newly created Factory however is coupled to the Request, which is fine as it is meant to convert Requests into Person objects. Hence we could even name it that way:
class Person { private String firstName; private String lastName; // .. more properties here Person(String firstName, String lastName, ...) { this.firstName = firstName; this.lastName = lastName; // ... } public void subcribeTo(Subscription subscription) { // do something interesting here } } class PersonFromRequestFactory { // .. dependencies here public Person create(HttpServletRequest request) { Person person = new Person(request.getParameter("firstName"), ) // .. read more properties // .. set up dependencies in Person, etc. } }
Once we have this Factory, you can take it a step further:
If you have different kind of request parameters to create the same object you could create different methods in the new Factory:
class PersonFromRequestFactory { // .. dependencies here public Person createFromRegistrationForm(HttpServletRequest request) { Person person = new Person(request.getParameter("firstName"), ) // .. read more properties // .. set up dependencies in Person, etc. } public Person createFromSubscriptionForm(HttpServletRequest request) { Person person = new Person(request.getParameter("givenName"), ) // .. read more properties // .. set up dependencies in Person, etc. } }
You could also create a Parameter object and go from there. For instance, if your web application uses Spring, you could wire your request parameters to an object (called “Form binding“) automagically and use that object as input in your Factory. This way it is type safe:
class PersonFromRequestFactory { // .. dependencies here public Person create(RegistrationForm form) { Person person = new Person(form.getFirstName(), ...) // .. read more properties // .. set up dependencies in Person, etc. } public Person createFromSubscriptionForm(SubscriptionForm form) { Person person = new Person(form.getGivenName(), ) // .. read more properties // .. set up dependencies in Person, etc. } }
But how do you test all this?
Did you notice the Person has private fields, and no get/set methods? The only way to set the fields is using the Person constructor. How do you test the correct construction of this Person class from the request? Since we are not able to read the properties, we have to use other ways to test that code. I’ll cover that in the next blog post.