For this reason, we are flexible with the search criteria with the knowledge that the business
logic of the system will do the right thing and return the best matches available.
Additionally, we are big fans of creating types to encapsulate concepts, even simple ones.
As you’ll see, Spring MVC isn’t restricted to working with only Stringclasses and primitive
types. The classes that encapsulate form submissions can be full of rich types, so don’t hesitate
to encapsulate types when appropriate.
With all the talk about building immutable classes, you might wonder why we decided to
add all these setters for this class. This class is not immutable (it includes public setters) for
two reasons: (1) the search criteria can change over time as the user refines his search to find
the best deals; and (2) we will take advantage of Spring MVC’s flexible usage of POJOs in order
to share this class across both the domain model (modeling the search criteria themselves)
and web requests. As you’ll see shortly, this class will be shared with the web layer to encapsu-
late the XHTML form submission data. It will be populated automatically by Spring MVC from
a form submission, so it must provide both getters and setters (Spring’s data binding can bind
only properties that follow JavaBean syntax and semantics).
Did we just allow advanced knowledge of the requirements of the web framework to influ-
ence the design of our domain model, but enforcing the existence of setters on any object that
will encapsulate forms? In this case we did, but we didn’t cross any dependency boundaries. In
fact, Spring MVC easily allows for domain objects to be used by the web tier, in order to cut
down on the amount of classes needed by the system.
As with issues brought up by the choice of your persistence framework, designing your
application by considering all the layers is a smart way to create a more cohesive architecture.
The domain model doesn’t have any compile-time dependencies on any other layers, so we’re
still safe.
The Flightclass (Listing 4-4) encapsulates an airline trip between two cities with zero or
more stops. Each stop along the way is an instance of a FlightLeg (Listing 4-5). A nonstop
flight, for instance, has only one FlightLeg. This class can also report the total amount of
travel time, via the getTotalTravelTime()method.
Along with getTotalTravelTime(), this class includes another business logic method named
isNonStop(). Not all business logic has to be big and complicated, but it is important to keep it
all in the object model (as much as you can, but be pragmatic about it). Calculated values (e.g.,
total travel time) or derived answers (e.g., is this flight nonstop?) should be answered by the
object you are talking about. Classes contain state andbehavior, so don’t forget to take advan-
tage of that.
Listing 4-4.Flight Class
public class Flight {
private List<FlightLeg> legs;
private BigDecimal totalCost;
public Flight(List<FlightLeg> legs, BigDecimal totalCost) {
Assert.notNull(legs);
Assert.isTrue(legs.size() >= 1, "Flights must have at least one leg");
46 CHAPTER 4 ■JUMP INTO SPRING MVC