The Maximal Decoupled “Parameterized Factory-Method-Pattern”
The first in a series of articles showing a new way of implementing the factory-method pattern in Java.
Join the DZone community and get the full member experience.
Join For Freeintroduction
in this first part of my upcoming series i’d like to show you a new way of implementing the “factory-method” pattern. to be more precise, it is what the famous “gang-of-four” call a “parameterized factory-method” in the design patterns-book (see the “implementation” section of the “factory method pattern” on page 110/111). for simplicity i will use the term “factory-method” synonym to “parameterized factory-method”. the crucial point here will be, that the factory no longer needs any compile-time dependencies upon any concrete interface implementation. furthermore i will explain how to write un-mocked unit-tests for a cdi-bean (the factory) in order to be able to check that all the cdi annotations work as desired without having to start an application server.
why decoupling is desirable
if you ask why such decoupling is desirable, then you most likely have not yet worked on a project, where almost all modules depended on each other. this is a nightmare in many different aspects, but be assured, that such a system will be very hard to change and maintain. thus always stick to uncle bob’s principle that any class or component should not depend on things that it doesn’t really need.
prerequisites
in order to understand this article, you should have a basic understanding of the java(tm) language and you also know what dependency injection is. i also recommend that you look for some basic cdi examples if you haven’t got any experience with cdi yet.
the factory-method-pattern basics by introducing the example
in the example that i will use throughout this article, i assume we have to create a system that receives match-results for various kinds of sport.
in the above picture, you see the basis for a standard “parameterized factory-method”-pattern:
- there is an interface, in our example it’s called “matchresultvalidator” with one or more generalized methods, here we have “validatematchresult()”
- there are sport-specific implementations of the interface, one for each type of sport: football, tennis, darts etc…
- there is the factory itself (“matchresultvalidatorfactory”). the factory-method receives one parameter, which is the object upon which the factory-method decides, which implementation the client actually needs. in our example the factory will make its decision upon the value object called “matchresult”.
the xsd for the example
in my example, i assume that we have an xml-based interface to our system. clients send xml-document instances of the root element called “matchresult”. while matchresult has some general attributes which are common to all kinds of sports, it also contains an xs:choice which binds a concrete instance of matchresult to a certain sport. here is the snippet from the xsd:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<xs:complextype name="matchresulttype">
<xs:sequence>
<xs:element name="hometeamid" type="xs:long"/>
<xs:element name="awayteamid" type="xs:long"/>
<xs:choice>
<xs:element name="footballresult" type="mr:timeperiodbasedgameresulttype" />
<xs:element name="handballresult" type="mr:timeperiodbasedgameresulttype" />
<xs:element name="icehockeyresult" type="mr:timeperiodbasedgameresulttype" />
<xs:element name="basketballresult" type="mr:timeperiodbasedgameresulttype" />
<xs:element name="tennismatchresult" type="mr:individualmatchesbasedgameresulttype" />
<xs:element name="tabletennismatchresult" type="mr:individualmatchesbasedgameresulttype" />
<xs:element name="billardmatchresult" type="mr:individualmatchesbasedgameresulttype" />
<xs:element name="dartsmatchresult" type="mr:individualmatchesbasedgameresulttype" />
</xs:choice>
</xs:sequence>
<xs:attribute name="leagueid" type="xs:long" use="required"/>
<xs:attribute name="matchid" type="xs:long" use="required"/>
</xs:complextype>
as you can see, one instance of matchresult can only be for one kind of sport. but many different sports share a similar kind of counting and result structure. thus i have designed two different result-structures that fit for many kinds of sports:
- the “timeperiodbasedgameresulttype” for sports like football where you have to halves or icehockey with three periods or basketball with four quarters and the outcome of each period is a score for each team. of course the sum of all period scores makes up the total score for each team.
- the “individualmatchesbasedgameresulttype” is for team-sports like tennis, tabletennis or darts where each team-member plays one or more single matches against one player from the other team and also plays at least one double match. each win in a single- or doublematch counts one point in the overall result.
of course you could find some more subtypes for matchresult, but for this example, 2 different kinds are enough. following you see an example for a football-matchresult:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<matchresult leagueid="4911" matchid="5012" xmlns="http://www.stephanbauer.me/modernizedpatterns/matchresult">
<hometeamid>4811</hometeamid>
<awayteamid>4711</awayteamid>
<footballresult>
<periodresult periodnumber="1">
<scorehometeam>2</scorehometeam>
<scoreawayteam>3</scoreawayteam>
</periodresult>
<periodresult periodnumber="2">
<scorehometeam>2</scorehometeam>
<scoreawayteam>0</scoreawayteam>
</periodresult>
</footballresult>
</matchresult>
as you can see, the subtype does not define how many periods it expects, because we want to reuse it for football, icehockey, basketball. thus we need a sports-specific validation of a matchresult on the server-side. and this is finally where our factory will come into play.
the deployment-structure of the example
before dependency injection (and especially cdi in our example), the factory was what “uncle bob” calls a “dependency magnet”, as it depended at compile-time on all concrete interface implementations (and transitively on their dependencies). with the following new, cdi-based solution, you can swap out the concrete interface implementations into separate “implementation”-modules, which the factory only needs to have available at runtime, but not at compile-time. this opens the doors for “independent develop-ability” of each concrete interface implementation which in turn makes it easier to split development tasks for specialized development teams or even external partners.
in my example, i assume that we have a war-file deployment called “matchresult-web” so that clients can send matchresults via a rest-interface. the rest-service is located in the “matchresult-web” module and directly uses the factory. this is in order to keep the example as simple as possible. in real life applications, you will probably have additional layers in between like a facade- and a business-logic-layer. finally, all the components will end up in the web-inf/lib of the war module.
my following explanations will focus on the blue components, because all the rest-service-related stuff has nothing to do with the factory-method-pattern itself. nevertheless, in order to make the example complete and allow for some integration-testing, i have added the war-module to the example code. but don’t worry, i will also show you how to unit-test such a cdi-based solution.
in the following diagram, i zoomed into the blue components in order to show you, which classes from the factory-method pattern go into which jar module:
the glue: defining cdi-qualifiers for each concrete implementation
the key to the desired decoupling of the factory from the concrete interface implementations are “cdi-qualifier-annotations”. each concrete implementation class must be annotated with its own special qualifier. in our example, we define a qualifier for each different kind of sport:
- @football
- @tennis
- @darts
- etc…
in the following snippet, you can see how the @football-qualifier-annotation is applied to the footballmatchresultvalidatorimpl-class:
@applicationscoped
@football
public class footballmatchresultvalidator implements matchresultvalidator {
…
}
the @football-qualifier-annotation itself is a normal java-annotation with the addition of the cdi- @qualifier-annotation:
@qualifier
@retention(runtime)
@target({
method, field, parameter, type
})
public @interface football {
}
the factory only knows the interface
in contrast to old-school-factory implementations, it is now possible, to define an instance variable for each concrete implementation by typing them all to the interface. thus all instance variables are of type “matchresultvalidator”. this is the key to make the factory independent of the interface implementation classes.
@applicationscoped
public class matchresultvalidatorfactory {
@inject
@football
private matchresultvalidator footballmatchresultvalidator;
@inject
@tennis
private matchresultvalidator tennismatchresultvalidator;
qualification of the injection points inside the factory
as you can see in the above snippet, the glue between the concrete implementations and the instance variables of the factory are the cdi-qualifier-annotations. by annotating the instance variable “footballmatchresultvalidator” with @football, we tell the cdi-container to inject the implementation of the interface which is itself annotated with @football. if there is none, then the cdi-container will fail on startup.
the factory-method: how to avoid large if-else cascades
simple case: 1:1-relation between valueobject-type and interface implementation
if we had a different java class for each kind of sport, then the factory can simply use a private map where the key is the “class<?>” of the value object and the map-value is the corresponding injected instance variable.
private final map<class<?>, matchresultvalidator> resultclasstovalidatormap = new hashmap<>();
this is not the case in our example, because we have the same root element type for all kinds of sport and it’s the choice inside the “matchresulttype” that makes the difference between the various kinds of sports. anyway, in case of a 1:1-relation, the implementation of the factory-method itself would be a simple lookup into the map.
please note that the population of the map must happen inside a @postconstruct-lifecycle method of the factory-bean. the reason is, that if you would do it in a constructor like in old-school-implementations, then the cdi-container does not yet have initialized the instance variables at that time and so you will effectively put null values into the map. i will demonstrate this also in the complex case below.
complex case: value-object must be queried to find the correct implementation
in our case, the factory must look into the given value object in order to determine the correct instance variable. the resulting code would look something like this:
if (matchresult.getfootballresult() != null) {
return this.footballmatchresultvalidator;
}
if (matchresult.gettennismatchresult() != null) {
return this.tennismatchresultvalidator;
}
if (matchresult.getxxx() != null) {
return this.xxxmatchresultvalidator;
}
// and so on...
throw new illegalargumentexception("unknown matchresult-typ!");
this is considered bad programming style, you should generally try to avoid large if-else cascades.
one nice way to do it differently is via java8 functional interfaces and lambda expressions each if-condition goes into a separate lambda expression based on “java.util.function.predicate”.
private final predicate isfootballmatchresult = tmr -> tmr.getfootballresult() != null;
private final predicate istennismatchresult = tmr -> tmr.gettennismatchresult() != null;
next, you still need a map to correlate each predicate to its instance variable and you populate the map in the @postconstruct lifecycle method:
private final map<predicate, matchresultvalidator> predicatetovalidatormap = new hashmap<>();
@postconstruct
public void postconstruct() {
predicatetovalidatormap.put(isfootballmatchresult, footballmatchresultvalidator);
predicatetovalidatormap.put(istennismatchresult, tennismatchresultvalidator);
}
the factory-method implementation now needs to iterate through the map entries, test each predicate and as soon as one predicate returns true, then it returns the corresponding map value. if no predicate returns true, an illegalargumentexception is thrown.
public matchresultvalidator getmatchresultvalidator(matchresult matchresult) {
predicate fittingpredicate = predicatetovalidatormap.keyset().stream().
filter(p -> p.test(matchresult)).findfirst().
orelsethrow(() -> new illegalargumentexception("unknown matchresult-type!"));
return this.predicatetovalidatormap.get(fittingpredicate);
}
if you are not yet used to the java8-syntax with the stream-api, then you can alternatively also write an old-school “imperative” for-loop.
unit-testing the factory
in order to be able to write unit tests for the factory-method, such that you can make sure that the qualifier-based dependency injection has been setup correctly, two additional solution blocks come into play (compared to plain unit tests):
- separate test-module to avoid cyclic dependencies between modules
- apache deltaspike framework for a convenient creation of a cdi-environment in a standard java vm.
avoiding cyclic dependencies between modules
usually a unit test is located in the same module as the production code that it wants to test. but for testing the correctly working dependency-injection, we need all the interface implementations in the classpath of the unit test.
in the productive war deployment, that’s no problem, because all the implementation modules are declared to be runtime-dependencies of the web application.
this means that the unit test – and so the module in which it is contained – must depend on all interface implementation modules. this would mean a dependency cycle because all these implementation modules already need to depend upon the factory-module, because this is where the interface is defined.
there are two solutions to this problem:
a) pull the interface out of the factory module and put it into a separate / new module.
b) create a separate test module for the factory-tests which can depend on all modules without any problem
i went for solution b) because i didn’t see a big benefit in separating the interface and the factory. the client will always need both of them. actually, the creation of an additional production module would have been driven solely by the way of testing. this seems a bit strange to me and so i think it fits better to create a separate test module (“matchresult-factory-api-test”).
once you have added the deltaspike-dependencies to the pom of the test-module, the unit test can be implemented in a very straight forward way:
- in line 20, the cditestrunner from deltaspike is used to execute this unit-test. it creates the cdi container in which the unit test will run.
- in lines 23/24 the “object under test”, the factory itself gets injected into the unit test.
-
that’s it! now the factory is fully initialized and can be tested as desired!
- in line 32, i use a static method of a utility class to create an instance of the value object “matchresult”.
- in line 33, i call the factory-method with this value object.
- and finally in lines 35, i assert that the returned implementation class is of the type i expected it to be.
Published at DZone with permission of Stephan Bauer, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments