Expert Spring MVC and Web Flow

(Dana P.) #1
There are three major issues with the preceding implementation. The first is that every
instance of CashRegisterImplhas a separate instance of PriceMatrixImpl. If it is costly to cre-
ate or maintain that object, then this is a waste of system resources. With heavy services (those
that are remote or those that require connections to external resources such as databases) it is
preferable to share a single instance across multiple clients.
The second and most important issue is that the CashRegisterImplnow has concrete
knowledge of the implementation of PriceMatrix. The CashRegisterImplclass should not
know the details of the implementation of its dependency interfaces. By explicitly creating
the instance of PriceMatrixImpl, the CashRegisterImplhas tightly coupled itself to the con-
crete implementation class.
The third issue with the preceding implementation is a direct result of the tight
coupling to the implementation class. By explicitly creating its own dependent objects, the
CashRegisterImplcreates a difficult test situation. One of the most important tenets of writing
unit tests is to divorce them from any environment requirements. The unit test itself should
run without connecting to outside resources. If we were to test the calculateTotalPrice
method as is, we would have no choice but to require a fully functioning PriceMatrixImpl.
Not only would this slow down our unit test runs, it would now couple our tests to resources
we can’t control. What if the price returned by lookupPricechanges over time? Our unit tests
would have to stay in sync with the physical resource, increasing the burden of maintaining
the tests.
If we can’t interact with a real PriceMatrix, how do we test our calculateTotalPrice
method? We will create a stub instance of PriceMatrix, one where we can control the condi-
tions and outcomes of the method calls. This technique is called a mock, and it is very useful
in unit tests. For a full explanation of mock objects and their uses, refer to JUnit in Actionby
Husted and Massol (Manning Publications, 2003). In the meantime, it is sufficient to think
about a mock object as a fake object that looks like a particular class, but whose behavior is
controlled by the test author.
As you can see, we have noticed three deficiencies of the above implementation. The
responsibility of creating the object is left to the method, prohibiting the use of a shared
PriceMatrixImpl. The method is also difficult to test, as we need to somehow insert a mock
object in place of the real thing. Most importantly, the client code is now aware of implemen-
tation details of its dependency, creating two tightly coupled classes.
To address the first issue, we will remove the explicit instantiation of the PriceMatrix
dependency. This frees the CashRegisterImplfrom the burden of object creation and from the
knowledge of any physical implementation details. More importantly, the PriceMatrixImplis
no longer located inside the CashRegisterImplinstance. By moving the dependency out of the
client object, it is no longer solely owned by CashRegisterImpl, and can now easily be shared
among all classes. The question then becomes, how do we now locate the dependency?

Service Locator


Enter the Service Locator pattern, our first attempt at fixing the method. The Service Locator
pattern encapsulates the actions taken to obtain a reference to the object required. This
shields the client from knowing how, or even where, to obtain a reference to the object.
This pattern emerged as a workaround from using Java Naming and Directory Interface
(JNDI) to obtain references to other Enterprise JavaBeans (EJBs) in a J2EE application. Using
JNDI to obtain a simple object reference can be cumbersome and can require a lot of defen-

12 CHAPTER 2 ■SPRING FUNDAMENTALS

Free download pdf