Design Patterns web based applications
A bit decent web application consists of a mix of design patterns. I'll mention only the most important ones.
Model View Controller pattern
The core (architectural) design pattern you'd like to use is the Model-View-Controller pattern. The Controller is to be represented by a Servlet which (in)directly creates/uses a specific Model and View based on the request. The Model is to be represented by Javabean classes. This is often further dividable in Business Model which contains the actions (behaviour) and Data Model which contains the data (information). The View is to be represented by JSP files which have direct access to the (Data) Model by EL (Expression Language).
Then, there are variations based on how actions and events are handled. The popular ones are:
Request (action) based MVC: this is the simplest to implement. The (Business) Model works directly with
HttpServletRequest
andHttpServletResponse
objects. You have to gather, convert and validate the request parameters (mostly) yourself. The View can be represented by plain vanilla HTML/CSS/JS and it does not maintain state across requests. This is how among others Spring MVC, Struts and Stripes works.Component based MVC: this is harder to implement. But you end up with a simpler model and view wherein all the "raw" Servlet API is abstracted completely away. You shouldn't have the need to gather, convert and validate the request parameters yourself. The Controller does this task and sets the gathered, converted and validated request parameters in the Model. All you need to do is to define action methods which works directly with the model properties. The View is represented by "components" in flavor of JSP taglibs or XML elements which in turn generates HTML/CSS/JS. The state of the View for the subsequent requests is maintained in the session. This is particularly helpful for server-side conversion, validation and value change events. This is how among others JSF, Wicket and Play! works.
As a side note, hobbying around with a homegrown MVC framework is a very nice learning exercise, and I do recommend it as long as you keep it for personal/private purposes. But once you go professional, then it's strongly recommended to pick an existing framework rather than reinventing your own. Learning an existing and well-developed framework takes in long term less time than developing and maintaining a robust framework yourself.
In the below detailed explanation I'll restrict myself to request based MVC since that's easier to implement.
Front Controller pattern (Mediator pattern)
First, the Controller part should implement the Front Controller pattern (which is a specialized kind of Mediator pattern). It should consist of only a single servlet which provides a centralized entry point of all requests. It should create the Model based on information available by the request, such as the pathinfo or servletpath, the method and/or specific parameters. The Business Model is called Action
in the below HttpServlet
example.
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Action action = ActionFactory.getAction(request);
String view = action.execute(request, response);
if (view.equals(request.getPathInfo().substring(1)) {
request.getRequestDispatcher("/WEB-INF/" + view + ".jsp").forward(request, response);
}
else {
response.sendRedirect(view); // We'd like to fire redirect in case of a view change as result of the action (PRG pattern).
}
}
catch (Exception e) {
throw new ServletException("Executing action failed.", e);
}
}
Executing the action should return some identifier to locate the view. Simplest would be to use it as filename of the JSP. Map this servlet on a specific url-pattern
in web.xml
, e.g. /pages/*
, *.do
or even just *.html
.
In case of prefix-patterns as for example /pages/*
you could then invoke URL's like http://example.com/pages/register, http://example.com/pages/login, etc and provide /WEB-INF/register.jsp
, /WEB-INF/login.jsp
with the appropriate GET and POST actions. The parts register
, login
, etc are then available by request.getPathInfo()
as in above example.
When you're using suffix-patterns like *.do
, *.html
, etc, then you could then invoke URL's like http://example.com/register.do, http://example.com/login.do, etc and you should change the code examples in this answer (also the ActionFactory
) to extract the register
and login
parts by request.getServletPath()
instead.
Strategy pattern
The Action
should follow the Strategy pattern. It needs to be defined as an abstract/interface type which should do the work based on the passed-in arguments of the abstract method (this is the difference with the Command pattern, wherein the abstract/interface type should do the work based on the arguments which are been passed-in during the creation of the implementation).
public interface Action {
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
You may want to make the Exception
more specific with a custom exception like ActionException
. It's just a basic kickoff example, the rest is all up to you.
Here's an example of a LoginAction
which (as its name says) logs in the user. The User
itself is in turn a Data Model. The View is aware of the presence of the User
.
public class LoginAction implements Action {
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = userDAO.find(username, password);
if (user != null) {
request.getSession().setAttribute("user", user); // Login user.
return "home"; // Redirect to home page.
}
else {
request.setAttribute("error", "Unknown username/password. Please retry."); // Store error message in request scope.
return "login"; // Go back to redisplay login form with error.
}
}
}
Factory method pattern
The ActionFactory
should follow the Factory method pattern. Basically, it should provide a creational method which returns a concrete implementation of an abstract/interface type. In this case, it should return an implementation of the Action
interface based on the information provided by the request. For example, the method and pathinfo (the pathinfo is the part after the context and servlet path in the request URL, excluding the query string).
public static Action getAction(HttpServletRequest request) {
return actions.get(request.getMethod() + request.getPathInfo());
}
The actions
in turn should be some static/applicationwide Map<String, Action>
which holds all known actions. It's up to you how to fill this map. Hardcoding:
actions.put("POST/register", new RegisterAction());
actions.put("POST/login", new LoginAction());
actions.put("GET/logout", new LogoutAction());
// ...
Or configurable based on a properties/XML configuration file in the classpath: (pseudo)
for (Entry entry : configuration) {
actions.put(entry.getKey(), Class.forName(entry.getValue()).newInstance());
}
Or dynamically based on a scan in the classpath for classes implementing a certain interface and/or annotation: (pseudo)
for (ClassFile classFile : classpath) {
if (classFile.isInstanceOf(Action.class)) {
actions.put(classFile.getAnnotation("mapping"), classFile.newInstance());
}
}
Keep in mind to create a "do nothing" Action
for the case there's no mapping. Let it for example return directly the request.getPathInfo().substring(1)
then.
Other patterns
Those were the important patterns so far.
To get a step further, you could use the Facade pattern to create a Context
class which in turn wraps the request and response objects and offers several convenience methods delegating to the request and response objects and pass that as argument into the Action#execute()
method instead. This adds an extra abstract layer to hide the raw Servlet API away. You should then basically end up with zero import javax.servlet.*
declarations in every Action
implementation. In JSF terms, this is what the FacesContext
and ExternalContext
classes are doing. You can find a concrete example in this answer.
Then there's the State pattern for the case that you'd like to add an extra abstraction layer to split the tasks of gathering the request parameters, converting them, validating them, updating the model values and execute the actions. In JSF terms, this is what the LifeCycle
is doing.
Then there's the Composite pattern for the case that you'd like to create a component based view which can be attached with the model and whose behaviour depends on the state of the request based lifecycle. In JSF terms, this is what the UIComponent
represent.
This way you can evolve bit by bit towards a component based framework.
See also:
- Examples of GoF Design Patterns in Java's core libraries
- Difference between Request MVC and Component MVC
- Show JDBC ResultSet in HTML in JSP page using MVC and DAO pattern
- What components are MVC in JSF MVC framework?
- JSF Controller, Service and DAO
Popular Design Patterns for Web Application Components
Those things are not design patterns. One source is enterprise integration patterns, another is Patterns of Enterprise Application Architecture.
What Design Patterns are mostly used in Web/Enterprise Applications?
I use Inversion of Control a lot.
In particular, when persisting / loading objects. It helps when we're not sure if the data is going to come from a database, a web service, or some other mechanism.
By using an interface and allowing multiple sources to expose a simple API for save / retrieving and allowing the object itself to know which API calls to make we end up with a very easy to manage architecture.
One example of this is here.
Suitable Design pattern for multi module web application
Honestly if that's the only scope of your application, keep it simple, don't get carried away trying to over-engineer or implement bunch design patterns unnecessarily.
there are different types of SMS to be sent and each type has its own
business logic to be applied before triggering the SMS
You have not mentioned how business logic differs based on SMS type. So in the simplest form you can start like this:
public interface ISMSService
{
void Send();
}
// One class for each SMS type
public class IndividualSMS : ISMSService
{
public IndividualSMS(<paramters>) {
// <parameters> can be different based on SMS type
}
public void Send() {
// Implement SMS type specific logic
}
}
public class SMSManager {
private readonly ISMSService smsService;
// Inject ISMSService implementation from calling code
public SMSManager(ISMSService smsService) {
this.smsService = smsService;
}
public void SendSMS() {
this.smsService.Send();
}
}
// Client code
var individualSMS = new IndividualSMS(<parameters>); // Use DI container for resolving
var smsManager = new SMSManager(individualSMS);
What design patterns are used in an ecommerce web apps?
There is a pattern called "Pattern: Microservice Architecture:"
Define an architecture that structures the application as a set of
loosely coupled, collaborating services. This approach corresponds to
the Y-axis of the Scale Cube. Each service is:
- Highly maintainable and testable - enables rapid and frequent
development and deployment- Loosely coupled with other services -
enables a team to work independently the majority of time on their
service(s) without being impacted by changes to other services and
without affecting other services- Independently deployable - enables a
team to deploy their service without having to coordinate with other
teams- Capable of being developed by a small team - essential for high
productivity by avoiding the high communication head of large teamsServices communicate using either synchronous protocols such as
HTTP/REST or asynchronous protocols such as AMQP. Services can be
developed and deployed independently of one another. Each service has
its own database in order to be decoupled from other services. Data
consistency between services is maintained using the Saga patternTo learn more about the nature of a service, please read this article.
And e-commerce application is considered as an example to apply pattern: Microservice Architecture.
So it is possible to create multiple services divided by entities or business domains:
- customers
- inventory
- shipping
Then it is necessary provide the way of communication among services. It can be event streaming platform Kafka.
Design pattern for a model-less web-application
What's important in an application, is not the design pattern used but properly addressing separation of concerns.
MVC is just an example in that direction. It allows you to separate the application data and all the logic that goes with it (Model) from the presentation of that data (View). User's interactions with the View is coordinated by the Controller who also transforms those interactions to actions to be performed by the Model.
A lot of applications fit into this behavior, so MVC is the obvious choice for them. If you think that MVC is overkill, then maybe go for a simplification of it like the Model Delegate (sometimes also referred as the Model/View Pattern). But again, the pattern is not important; what's important is to properly separate the responsibilities within the application.
In your comments you mention that your application is already MVC, so I would leave it at that. I can't see how that's overkill and as your application will grow (and I'm sure it will) you'll be glad it was designed like that from the start.
What design pattern is this web application using, if any? MVC and/or SPA?
It's not MVC, although I do not know what it's called. It could be the basis for an MVC setup using something like emberJS, AngularJS, GWT, etc, but this setup is too generic to draw that conclusion.
It is however a very nice setup that I use a lot. First calling in the static HTML as a one pager that contains all the templates and then pulling in the data using JavaScript calls. I personally prefer to not include any user specific content in the initial HTML so it is highly cashable (even in a CDN if needed) and only pull in user data through AJAX calls.
Related Topics
How to Deal With "Java.Lang.Outofmemoryerror: Java Heap Space" Error
How to Fix a Nosuchmethoderror
What Is Pecs (Producer Extends Consumer Super)
Reading a Plain Text File in Java
Understanding Checked VS Unchecked Exceptions in Java
How to Round a Number to N Decimal Places in Java
Change Date Format in a Java String
Non-Static Variable Cannot Be Referenced from a Static Context
Show Jdbc Resultset in HTML in Jsp Page Using MVC and Dao Pattern
How Do the Post Increment (I++) and Pre Increment (++I) Operators Work in Java
When to Use Linkedlist Over Arraylist in Java
Why Are Only Final Variables Accessible in Anonymous Class
How to Use Java.Util.Scanner to Correctly Read User Input from System.In and Act on It
Why Is It Considered a Bad Practice to Omit Curly Braces