Bringing Design Patterns to the Front‑End
In many J2EE applications the data layer quickly becomes over‑engineered. The patterns we covered earlier - Iterator, DAO, and Value Object - are often combined without clear separation. Code Sample 7 illustrates a clean separation: the iterator logic stays identical to the earlier example, but the DAO now hands back a collection of immutable value objects that bundle all service attributes. The servlet simply pulls the StartIndex and ListSize parameters, hands them to the DAO, receives a PageByPageIterator instance, and then works with the collection of value objects. Because the objects are immutable, the servlet, JSP, or any other component cannot change its state, which eliminates synchronization overhead and preserves consistency between server and client.
When the servlet iterates over the collection, it does not need to perform any extra database lookups for each service record. The DAO has already populated each value object with all of the columns required for the front end. The PageByPageIterator guarantees that the collection contains only the slice of data requested by the user, keeping the memory footprint small and the response fast. This approach is a textbook example of the Fast Lane Reader pattern: read only, bulk data retrieval in a single round‑trip to the persistence layer.
The value objects are a natural fit for this pattern because they are lightweight, serializable, and immutable. Serialization allows them to travel across the network or be stored in a session without risk of accidental mutation. Immutability guarantees that once a DAO creates a value object, the servlet, JSP, or any other component cannot change its state, which eliminates synchronization overhead and preserves consistency between server and client. In high‑traffic scenarios, the same value objects can be cached in an in‑memory store, such as a Guava cache or Ehcache, to serve identical requests without hitting the database again.
In practice, many teams cache frequently accessed value objects in an in‑memory store to reduce the load on the DAO. Because the objects are immutable, the cache can safely share them across threads without synchronization. However, developers must be aware that caching can surface stale data if the underlying database updates are not reflected in the cache eviction policy. A common strategy is to use a short time‑to‑live (TTL) for cached value objects or to trigger cache invalidation on write operations. Overall, combining these patterns reduces network traffic, improves response time, and provides a clean, modular architecture that separates persistence concerns from presentation logic.
Another benefit of the Value Object pattern is that it decouples the database schema from the view layer. If the table structure changes, only the DAO and the value object classes need to be updated; the servlet and JSP pages remain untouched. This reduces regression risk and makes the codebase more maintainable. For example, adding a new service attribute such as “serviceLevel” requires adding a new field to the ValueObject class, extending the DAO query, and updating the JSP to display the new field. The rest of the system continues to function without modification.
The servlet shown in Code Sample 7 illustrates a typical pattern: it pulls request parameters, delegates to the DAO, and iterates over the returned collection. The servlet does not need to know the details of how the value objects were constructed, nor does it need to manage the iterator state. All of that complexity lives inside the DAO layer. This separation of concerns allows developers to focus on business logic in the servlet and keep persistence logic isolated, making both layers easier to test and evolve independently.
In addition, unit tests should verify that the DAO returns the expected value objects, and that the servlet correctly handles missing parameters or null values. This defensive coding protects the application from runtime errors.
Overall, the combination of the Iterator, DAO, and Value Object patterns creates a robust, low‑coupling architecture that scales well with larger data sets and higher traffic. By limiting the amount of data transferred per request, by caching immutable objects, and by keeping the servlet logic free of persistence concerns, teams can deliver fast, reliable web services that are easier to maintain and extend over time.
Performance Tips for Remote Data Retrieval
When a user requests a list of services, the servlet normally would issue a separate database query for each service name or for each page of results. The Fast Lane Reader pattern flips that approach: the DAO performs a single bulk query that returns a PageByPageIterator populated with a collection of value objects. The servlet simply consumes that iterator, extracts the required attributes, and forwards them to the JSP. Because all data for the requested page is already in memory, the servlet never needs to touch the database again. This single round‑trip reduces latency, lowers server load, and gives the front end a predictable response time.
Value objects are a natural fit for this pattern because they are lightweight, serializable, and immutable. Serialization allows them to travel across the network or be stored in a session without risk of accidental mutation. Immutability guarantees that once a DAO creates a value object, the servlet, JSP, or any other component cannot change its state, which eliminates synchronization overhead and preserves consistency between server and client. In high‑traffic scenarios, the same value objects can be cached in an in‑memory store, such as a Guava cache or Ehcache, to serve identical requests without hitting the database again.
The Fast Lane Reader pattern is not limited to read‑only data. If the application requires updates, the same value objects can be sent back to the server. The servlet can deserialize the received objects, validate them, and hand them to a service layer that updates the underlying database via the DAO. Because the objects are immutable on the client side, the server can safely treat them as DTOs and avoid accidental changes to domain entities. This bidirectional usage keeps the persistence layer decoupled from the web tier and simplifies transaction handling.
There is an inherent trade‑off: introducing value objects, iterators, and caching adds some upfront development effort and a modest increase in code complexity. However, the performance gains are often substantial, especially for applications that serve thousands of users and large data sets. The J2EE Blueprints program provides fully‑worked examples of these patterns, including UML diagrams, deployment scripts, and performance benchmarks. Looking ahead, the next version of EJBs introduces local interfaces that reduce the cost of remote calls even further. Incorporating these new capabilities can make the combination of iterator, DAO, and value object patterns even more efficient.
Finally, unit tests should verify that the DAO returns the expected value objects, and that the servlet correctly handles missing parameters or null values. This defensive coding protects the application from runtime errors. In addition, monitoring and profiling tools like JProfiler or VisualVM can identify bottlenecks. If a bottleneck is found, fine‑tuning the cache size or adjusting the page size of the iterator can yield additional gains.
In practice, teams often combine these patterns with modern async frameworks or microservices. For instance, a RESTful endpoint can expose the same value objects as JSON, while an Angular or React front end consumes them. The immutable nature of the objects plays well with client‑side state management libraries like Redux, where immutability guarantees predictable state transitions. On the server side, the DAO can be backed by a read‑through cache such as Redis, providing an even faster response for repeated queries. By integrating these complementary technologies, the overall system remains both performant and maintainable.
References
1. Design Patterns section of the J2EE Blueprints Program at http://java.sun.com/j2ee/blueprints.
2. F. Buschmann, R. Meunier, H. Rohnert, P. Sommerlad, M. Stal. Pattern‑Oriented Software Architecture: A System of Patterns. John Wiley & Sons Ltd., 1996.
3. Martin Fowler's Information System Architecture at http://martinfowler.com/isa/index.html.
4. E. Gamma, R. Helm, R. Johnson, J. Vlissides. Design Patterns: Elements of Reusable Object‑Oriented Software. Addison‑Wesley, 1995.
5. “Gang of Four” Patterns Template at http://hillside.net/patterns/Writing/GOFtempl.html.





No comments yet. Be the first to comment!