Chapter 11
Web Presentation Design Patterns
Introduction
To organize the web presentation, the design patterns of this category can be divided into the following seven main sections:
Model view controller: Designing User Interface (UI) interactions are divided into three different roles.
Page controller: An object handles requests for a page or action on a website.
Front controller: A controller is responsible for managing all incoming requests.
Template view: By placing a series of markers in HTML pages, various information can be displayed on the pages at runtime.
Transform view: It can process the existing data and convert it to the user's preferred format.
Two-step view: The data in the model is converted into HTML format in two steps.
Application controller: It can centrally manage the movement between pages and the overall flow of the program.
Structure
In this chapter, we will cover the following topics:
Web presentation design patterns
Model view controller
Page controller
Front controller
Template view
Transform view
Two-step View
Application Controller
Objectives
In this chapter, you will learn how to organize the user interface. You will also learn about design patterns in this field. In this chapter, you will learn how to separate the data, logic, and display parts from each other so that each part can be implemented in a useful and appropriate way.
Web presentation design patterns
One of the most significant changes in enterprise applications in recent years is the penetration of web-based user interfaces. These interfaces come with various advantages, including that the client often does not need to install a special program to use them. Creating web applications is often accompanied by the generation of server-side codes. The request is entered into the web server, which delivers the request based on the web application's content or the corresponding website.
The model view controller design pattern can separate the display-related details from the data structure and logic. In this structure, the controller receives the request, and the data is received from the data source by the model. Then, based on the results, the controller returns the appropriate view in the response, and the user sees the desired view.
Sometimes, a central engine is needed in the structure to manage the movement between different pages. In this case, you can use an application controller. If there is different and complex logic for the order between the displays in the program, the application controller can have a significant impact.
You can benefit from three different design patterns for the view section: Transform view, template view, and two-step view. Markers are used in template view and then replaced with dynamic content. You can use transform view to create a view based on the domain model. Both patterns provide the possibility of single-step views. But sometimes, it is necessary to first convert the data into a logical representation, then convert the logical representation into the view desired by the user. In this case, a two-step view will be useful.
The next part to pay attention to in the discussion of web display is to pay attention to the controllers. One method for controllers is to have one controller per page on the website. This method, which is the simplest type, can be implemented through a page controller. But usually, having a controller for one page will complicate the code. Most of what the controller does can be divided into two parts. Part 1) receiving the HTTP request and part 2) deciding what processing should be done for an incoming request. Therefore, it is better to separate these two parts from each other. In this regard, you can get help from Front Controller.
Model view controller
Name:
Model view controller
Classification:
Web presentation design patterns
Also known as:
MVC
Intent:
Using this pattern, the design of user interface interactions is divided into three different roles, which are view, model, and controller:
Model: It is an object that provides some information about the domain. All the data and behaviors related to them are presented through the model. In an object-oriented approach, the model can be considered an object within the domain model.
View: Data can be displayed in the UI through this section. The only task of this section is to display information and manage user interactions. In web applications, this section usually includes HTML codes.
Controller: Through this section, the data is received from the view, placed in the model, and it causes the view to be updated accordingly.
Motivation, Structure, Implementation, and Sample code:
With the preceding explanation, UI can be considered a combination of view and controller. We are planning to design a login form, and we intend for the user to enter his/her page by entering his/her username and password and see his/her username and password next to his/her name.
According to the preceding requirement, the model class can be considered as follows:
public class LoginModel
{
public string UserName { get; set; }
public string Password { get; set; }
public string FullName { get; set; }
}
As you can see, the Model class has three properties for UserName, Password, and FullName.
The codes related to the controller can also be considered as follows:
public class UserController
{
private IView view;
public IView LoginIndex()
{
view = new LoginView();
view.Display();
return view;
}
public IView DashboardIndex(LoginModel model)
{
if (model == null)
return LoginIndex();
else
{
model.FullName = "Vahid Farahmandian";
view = new DashboardView(model);
view.Display();
}
return view;
}
public IView Login(LoginModel model)
{
if (model.UserName == "vahid" && model.Password == "123")
return DashboardIndex(model);
else
return LoginIndex();
}
public IView Logout() => LoginIndex();
}
In the preceding code, the LoginIndex method is responsible for returning the view related to Login. The login form is displayed to the user when this method is called. The DashboardIndex method is like this one and returns the View related to the user panel. Besides these two methods that return views, there are also two other methods. By receiving the user's inputs, the Login method performs the necessary validations and decides whether to log in to the user or not. The Logout method also receives the user's request and, while removing the user from the user account, returns him/her to the login page. As it is clear in the controller codes, the controller communicates with the model by receiving the user's inputs, values the object related to the model, and establishes the connection between View and Controller.
The codes related to View can also be imagined as follows:
public class LoginView : IView
{
readonly LoginModel model;
readonly UserController controller;
public LoginView()
{
model = new LoginModel();
controller = new UserController();
}
public void Display()
{
Console.WriteLine($"Enter username:");
model.UserName = Console.ReadLine();
Console.WriteLine($"Enter password:");
model.Password = Console.ReadLine();
}
public IView Login() => controller.Login(model);
}
The preceding codes show the codes related to the login view. This class has a method named Display which displays the corresponding form by calling it. Also, after entering the username and password, the user sends the information to the controller by pressing the login button. The Login method is embedded in this class to simulate this. The codes related to the view of the user panel will be similar to these codes. As follows:
public class DashboardView : IView
{
readonly LoginModel model;
readonly UserController controller;
public DashboardView(LoginModel model)
{
this.model = model;
controller = new UserController();
}
public void Display()
=> Console.WriteLine($"Username: {model.UserName},
Password: {model.Password},
FullName: {model.FullName}");
public IView Logout()
{
Console.WriteLine("User logged out successfully");
return controller.Logout();
}
}
As it is clear in the preceding codes, View receives data from the user and sends it to the Controller or takes it from the Controller and displays it in the output.
Note that in the preceding code, an attempt has been made to show the various components of the MVC design pattern in the form of C#.NET codes with a simple example.
Notes:
Transaction script can be considered a type of model because we have nothing to do with the user interface in writing transaction script.
Using the Microsoft ASP.NET MVC framework, web applications can be created using the MVC design pattern.
This design pattern can be used in non-web applications as well.
This design pattern indicates two types of separation. The first is to separate the View from the model, and the second is to separate the Controller from the View. It is very important to separate the model from the View. One of the reasons for this is that the way of display and the work related to the model are two different concerns and should not be addressed simultaneously. Also, this separation allows a model to be presented to the end user in different ways (Web Page, Web API, and so on) and in different formats (login form, user panel form, and so on). Separating the controller from the view is less important today, with different frameworks for UI. The role of the controller is changing, and most of the controller part is placed between the view and the model. Application controller design patterns can be very helpful in this case to clarify the issue.
Combining this design pattern with the observer design pattern can be very useful. In this case, the view can be updated automatically by applying changes to the model.
Consequences: Advantages
Due to the separation of the view from the model, it can be tested independently.
Using this design pattern, the complexity can be better managed with the help of three divisions.
It is easier to maintain and develop the code in general.
The principle of Separation of Concern (SoC) is better observed.
Consequences: Disadvantages
The amount of code in the controller can be large and threaten the code's maintenance.
It is more difficult to read and make changes to the code.
Applicability:
Except in small systems, where the model does not contain specific behavior, in the rest of the systems, using this design pattern can be very useful.
Related patterns:
Some of the following design patterns are not related to the Model View Controller design pattern, but to implement this design pattern, checking the following design patterns will be useful:
Transaction script
Application controller
Observer
Page controller
Name:
Page Controller
Classification:
Web presentation design patterns
Also known as:
---
Intent:
Using this design pattern, an object handles the requests of a page or action on a website. In fact, in this design pattern, there is a controller for each page.
Motivation, Structure, Implementation, and Sample code:
Suppose there is a requirement, and, in its format, we need to display the user's name and surname after receiving the user's national code. Using the page controller design pattern, there are two parts to implementing this requirement. The first part is the view part, and the second is the business logic part. The logic section is the combination of the controller and model.
Suppose we want to use ASP.Net web forms to implement this requirement. Using this technology, the view section is the same as the web form pages, which are composed of HTML codes, and the logic section is the code behind it. Now, to implement the preceding requirement, the following codes can be imagined for the View section:
<%@Page Language="C#" Codebehind="Inquiry.aspx.cs" AutoEventWireup="false" Inherits="Inquiry" %>
As it is clear in the above code, in the first line, it is specified in which file the logic related to the above View is located. (CodeBehind="Inquiry.aspx.cs"). It is also clear from the preceding code that when the btnInquiry button is clicked, which method should be executed on the server side. The codes related to Code Behind are as follows:
public class Inquiry : System.Web.UI.Page
{
protected System.Web.UI.WebControls.TextBox name;
protected System.Web.UI.WebControls.Button MyButton;
protected System.Web.UI.HtmlControls.HtmlGenericControl mySpan;
public void btnInquiry_Click(Object sender, EventArgs e)
{
var info = DatabaseGateway.Find(txtNationalCode.Text);
if(info==null)
result.InnerHtml="Not found";
result.InnerHtml = $"First name and Last name:
{info.Name} {info.LastName}";
}
}
According to the preceding code, when the user enters the national code in txtNationalCode, he/she clicks on the inquiry button. By clicking on this button, the Click event related to the button is called, and in response to this event, the btnInquiry_Click method is called. In this method, the national code value is read, the information is fetched from the database using the DatabaseGateway helper class, and the result is sent to view again.
Notes:
The front controller design pattern and this design pattern describe two different methods for implementing the controller part in the MVC pattern.
The page controller design pattern concept is implemented by default in ASP.NET.
When using this design pattern, duplicate codes will also increase over time and as the number of pages increases. One class can be used as the parent of all classes to reuse codes, and common codes can be transferred to that class. For example, as follows:
Public class Inquiry: BaseController{…}
The preceding code has transferred the repeated codes to the BaseController class.
There are usually two categories of codes in Code Behind. Codes depend on the graphical interface, and codes are independent of the interface. It is usually possible to transfer independent codes from the graphical interface to the parent class. You can benefit from the template method design model to better implement this relationship.
Using the front controller design pattern is better to better manage the complexity in larger programs.
Consequences: Advantages
Since this design pattern is implemented by default in ASP.NET, you can use the features in the framework with minimal effort.
Since each controller has only one page, the codes in the controller include a smaller range of the program and increase simplicity.
By using parent controllers, the possibility of code reuse increases.
By using helper classes, you can develop tasks that can be done in the controller. For example, a helper class can communicate with an information link. Along with inheritance, this method is another method to increase code reusability.
Consequences: Disadvantages
Testing using this design pattern is difficult. Especially if the ASP.Net web form is used, the controllers must have inherited the System.Web.UI.Page class, and it will not be easy to sample from this class. In this case, the only possible way to test is to send an HTTP request and check the received response, which is also prone to errors.
As the number of pages increases or the program becomes more complex and requires more dynamic settings for pages, this design pattern will not be suitable for larger and wider programs.
The use of inheritance to increase reusability, along with all its benefits, makes the code more complicated. Over time, the inheritance hierarchy also becomes more complicated, and the maintenance of the code decreases greatly.
Applicability:
It can be useful for implementing small systems or systems with simple business logic.
Related patterns:
Some of the following design patterns are unrelated to the Page Controller design pattern. To implement this design pattern, checking the following design patterns will be useful:
Front controller
Model view controller
Template method
Front controller
Name:
Front Controller
Classification:
Web presentation design patterns
Also known as:
---
Intent:
Using this design pattern, a controller is responsible for handling all incoming requests. This controller is sometimes called a handler.
Motivation, Structure, Implementation, and Sample code:
Suppose a requirement is raised and requested in its format that before responding to any request, the request log is recorded first and then checked whether the user is authenticated in the system. If it was authenticated, their request will be processed; otherwise, an error message will be displayed to the user.
Let us also assume that we have two different controllers to manage requests related to books and publishers, called BookController and AuthorController:
public class BookController
{
public void Get()
{
Console.WriteLine("Design Patterns in .NET");
Console.WriteLine("C# Programming");
}
}
public class AuthorController
{
public void Get()
{
Console.WriteLine("Vahid Farahmandian");
Console.WriteLine("Ali Rahimi");
Console.WriteLine("Reza Karimi");
}
}
To implement the preceding requirement, a simple way is to register the log and check the authentication at the beginning of the methods of each of these controllers. This method has several important drawbacks, including writing repetitive codes and difficulty applying changes.
But another solution is that a controller receives all the requests, registers the log, performs the user authentication process, and finally sends the request to the appropriate controller.
For this, we first define a Dispatcher. Its duty is to direct the request to the controller after receiving the request as follows:
public class Dispatcher
{
BookController bookController;
AuthorController authorController;
public Dispatcher()
{
bookController = new BookController();
authorController = new AuthorController();
}
public void Dispatch(string request)
{
if (request.Contains("/book/"))
bookController.Get();
else
authorController.Get();
}
}
As it is clear in the preceding code, the Dispatch method receives the request and, according to that, directs the request to one of the BookController or AuthorController controllers.
Now that the Dispatcher has been implemented, the front controller is needed to receive the requests and perform log registration and authentication operations. For this, we define the front controller as follows:
public class MainHandler
{
private Dispatcher dispatcher;
public MainHandler() => dispatcher = new Dispatcher();
private bool IsAutheticated() => true;
private void SetLog(string request)
=> Console.WriteLine($"Request received: {request}");
public void ReceiveRequest(string request)
{
SetLog(request);
if (IsAutheticated())
dispatcher.Dispatch(request);
else
throw new Exception("Unauthenticated user error");
}
}
As seen in the preceding code, all requests are first entered into the MainHandler. Within this class and the ReceiveRequest method, we perform tasks related to log registration and authentication verification. If everything is correct, the request will be delivered to the Dispatch method in the Dispatcher class, and this method will deliver the request to the appropriate Controller. The preceding example is a very simple example of this design pattern.
Notes:
Combining this design pattern with the decorator design pattern can be very useful.
If the only reason for choosing this design pattern is to reduce the amount of code, then probably using the page controller design pattern and benefiting from inheritance to manage the duplicate code will be a better solution.
The dynamic approach can also be used in the design of the Dispatcher class. In this method, the target classes can be dynamically identified during execution, and the request can be directed to them.
Consequences: Advantages
Using this design pattern reduces the volume of repetitive codes, and it is easy to make changes.
Consequences: Disadvantages
Compared to the page controller design pattern, it will be more complicated and, therefore, unsuitable for simpler scenarios.
Applicability:
If it is necessary to perform an operational request such as authentication control, access control, and so on, then using this design pattern can be useful.
Related patterns:
Some of the following design patterns are unrelated to the Front Controller design pattern. To implement this design pattern, checking the following design patterns will be useful:
Decorator
Page controller
Template view
Name:
Template View
Classification:
Web presentation design patterns
Also known as:
---
Intent:
Using this design pattern, placing a series of markers in HTML pages, various information can be displayed on the pages at runtime.
Motivation, Structure, Implementation, and Sample code:
Suppose there is a requirement, and we want to display the list of authors on the page as a table. We also want to display the author's name with the most books on the table. When the content we want to present is static, there is no problem designing the view section. The complexity starts when the content of the view section itself becomes dynamic, and the content of this section needs to be the result of a series of calculations or processes.
There are different methods for this. One suitable method is to design the view with the help of a series of markers in the view section and then move these markers with real data in the controller section and use helper classes for each view. To implement this requirement, we consider the following model:
public class Author
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int BooksCount { get; set; }
}
In the preceding model, the BooksCount feature displays the number of books by each author. To get the list of authors and the number of their books, refer to the following code to get help from the Helper class :
public class AuthorHelper
{
public List
{
return new List
{
new Author
{
FirstName="Vahid",
LastName="Farahmandian",
BooksCount=2
},
new Author
{
FirstName="Ali",
LastName="Rahimi",
BooksCount=1
},
new Author
{
FirstName="Hassan",
LastName="Abbasi",
BooksCount=3
}
};
}
}
In the GetAuthors method, you can connect to the database and get the list of authors from the database. ASP.NET web form has been used to design the View in this scenario so that the role and effect of the indicators can be easily displayed. With these explanations, View can be considered as follows:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AuthorsList.aspx.cs" Inherits="WebApplication1.AuthorsList" %>
Best Author:
As shown in the preceding HTML code, inline expressions in .NET have been used as pointers to set the fistName and lastName labels. The code corresponding to the preceding View To set the BestAuthor attribute is also defined as follows in the Code Behind:
protected Author BestAuthor { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
var helper = new AuthorHelper();
Authors = helper.GetAuthors();
BestAuthor = Authors.OrderByDescending(x => x.BooksCount).FirstOrDefault();
firstname.DataBind();
lastname.DataBind();
}
According to the preceding code, when the page is loaded, the author with the most books is identified, and his information is placed in the BestAuthor feature. Then, the available indicators are placed in the View with appropriate values, and the page is loaded. According to the preceding codes, the final HTML code sent to the user's browser will be as follows:
Best Author:
Hassan
Abbasi
As you can see, the markers in the View are placed with appropriate values. In the following, different ways can be used to display the list of authors. ASP.NET web form has provided a component called DataGrid for the tabular display of data, which can be used in View as follows:
The preceding code shows that the DataGrid will have three columns displaying the author's information. To assign values to this DataGrid, you can do the following in Code Behind:
var helper = new AuthorHelper();
Authors = helper.GetAuthors();
authorsGrid.DataSource = Authors;
authorsGrid.DataBind();
With the preceding description, the code for the View section will be as follows:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AuthorsList.aspx.cs" Inherits="WebApplication1.AuthorsList" %>
Also, the final code in Code Behind will be as follows:
public partial class AuthorsList : System.Web.UI.Page
{
protected List
protected Author BestAuthor { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
var helper = new AuthorHelper();
Authors = helper.GetAuthors();
authorsGrid.DataSource = Authors;
authorsGrid.DataBind();
BestAuthor = Authors
.OrderByDescending(x => x.BooksCount)
.FirstOrDefault();
firstname.DataBind();
lastname.DataBind();
}
}
Notes:
The main idea behind this design pattern is to design HTML pages with a series of markers to provide dynamic content. When these pages are requested, the markers are placed on the server side with appropriate values, and the response is returned to the client.
Codes that contain programming logic and are placed in view are called scriptlets.
You can use Helper classes and implement the desired logic to prevent scriptlet placement on the page. The implementation of this logic is sometimes complicated. For example, it is possible to display male authors in yellow and female authors in blue in a table. Returning the HTML tag instead of the value in the server-side codes is one of the ways to prevent scriptlet placement in the View codes. The problem with this method will be the difficulty of maintaining the code.
To display a data list in View, there are different methods. One of these ways is to write a loop and form a line for each record. Another way is to use the templates provided by the technology used. For example, DataGrid can be useful for this purpose.
To implement the View section in MVC, choose between template view, transform view, and two-step view design patterns.
Consequences: Advantages
If there are not many scriptlets on the page, the graphic design of the pages is possible according to the structure of the pages in a simple way. This makes it easy for graphic designers to design pages.
Consequences: Disadvantages
If many scriptlet codes are placed in View, it will be difficult for non-programmers, such as graphic designers, to understand View.
Testing using this design pattern is difficult.
Applicability:
This design pattern can be used to implement the View section in MVC.
Related patterns:
Some of the following design patterns are not related to the Template View design pattern, but to implement this design pattern, checking the following design patterns will be useful:
Transform view
Two-step view
Model view controller
Transform view
Name:
Transform view
Classification:
Web presentation design patterns
Also known as:
---
Intent:
Using this design pattern, the existing data can be processed and converted into the user's preferred format. The preferred format is usually HTML, but sometimes it may be necessary to convert the data to XML or JSON, or any other format.
Motivation, Structure, Implementation, and Sample code:
Suppose we need to get the list of authors from the database, convert it into HTML format, and display it in the output. Due to the problems of the template view design pattern, we want to use the transform view design pattern for this.
For this, we first need to get the list of authors from the database or any other data source. Therefore, we have the following codes for this:
public class Author
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int BooksCount { get; set; }
}
public class DatabaseGateway
{
public List
{
return new List
{
new Author
{
FirstName="Vahid",
LastName="Farahmandian",
BooksCount=2
},
new Author
{
FirstName="Ali",
LastName="Rahimi",
BooksCount=1
},
new Author
{
FirstName="Hassan",
LastName="Abbasi",
BooksCount=3
}
};
}
}
According to the preceding codes, we have received the list of authors. Now, before we deliver this list to View, we need to process it and convert it to the HTML format the user desires. There are different ways to do this. One of the ways is to convert this list into XML format and then convert it to desired HTML format with the help of XSLT. Another simple way is to process the list and generate the HTML tags using a loop. For the sake of simplicity, we will consider the second way here. For this purpose, the desired method can be written as follows:
public string Transform(List
{
StringBuilder sb = new();
sb.AppendLine("");
sb.AppendLine("
");sb.AppendLine("
");sb.AppendLine("
{item.Name} | ||
{item.FirstName} | {item.LastName} | {item.BooksCount} |
");
sb.AppendLine("");
sb.Append("");
return sb.ToString();
}
As seen in the preceding method, the data is entered into this method as input, and inside this method, it is converted into the user's desired format. After the output is ready, it can be presented and displayed directly to the user. This method is called Transformer.
Notes:
Using generics, reflection, or nested loops and return methods, you can implement the Transformer method in such a way that it can be used to convert various types of objects to HTML.
If Transformer is defined as generic, it can reuse the code.
Consequences: Advantages
Using this design pattern makes it possible to test better than the Template View design pattern.
Consequences: Disadvantages
Providing views of the most complex design pattern will increase complexity.
Applicability:
This design pattern can be used to implement the View section in MVC.
Related patterns:
Some of the following design patterns are not related to the Transform View design pattern, but to implement this design pattern, checking the following design patterns will be useful:
Template view
Model view controller
Two-step view
Name:
Two Step View
Classification:
Web presentation design patterns
Also known as:
---
Intent:
Using this design pattern, the data in the model are converted into HTML format in two steps. In the first stage, this data structure is converted into a logical structure; in the second stage, this logical structure is converted into HTML.
Motivation, Structure, Implementation, and Sample code:
Suppose we are displaying the list of authors in the form of a table to the user. Besides the list of authors, we also have the list of publishers and books. A requirement has been raised for the table rows to have one of the different background colors. We need to refer to and change each table to apply this change. But there is another solution, and that is to use the two-step view design pattern.
If we can convert existing models into an intermediate logical structure, then we can convert this logical structure into HTML codes using a converter. For this, we first examine the first stage of this design pattern: the production of a logical structure.
There are different methods to generate a logical structure, but we use XML and XSLT methods for easier and better understanding. Suppose we have the authors' data in XML format in the following form:
If you are unfamiliar with XML, it is recommended to get familiar with it through the link: https://www.w3schools.com/xml/xml_whatis.asp.
However, to clarify the example, the above XML structure and the following JSON structure are equivalent. Of course, we will proceed with the XML structure in the following explanations:
{
"authors": {
"author": [
{
"firstname": "Vahid",
"lastname": "Farahmandian",
"booksCount": 2
},
{
"firstname": "Ali",
"lastname": "Rahimi",
"booksCount": 1
},
{
"firstname": "Hassan",
"lastname": "Abbasi",
"booksCount": 3
}
]
}
}
We convert the preceding XML structure into an expected logical structure using an XSLT converter to generate a logical structure. The XSLT converter can be defined as follows:
As seen in the preceding XSLT structure, the model previously mentioned in the XML structure is converted into the expected logical format with this structure. For example, in this format, it is said that whenever you reach authors, define the equivalent structure
. To apply this XSLT to the said XML, you can use the following code:
public void FirstStepTransformer()
{
var myXslTrans = new XslCompiledTransform();
myXslTrans.Load(@"firststep-style.xslt");
myXslTrans.Transform(@"input.xml", @" logical.xml");
}
The result of executing this code will be the following output:
As seen in the preceding output, the format defined in XSLT is applied to the input XML and the output is generated. This output is the first step in the two-step view design pattern. To produce the output of the second step, which is often the output in HTML format, similar steps but with a different XSLT format must be followed. Therefore, we can define the XSLT required to generate the desired HTML as follows:
As seen in the preceding code, the output of the first step is converted to HTML using this format. Using this XSLT structure, HTML output will be generated as follows:
Vahid | Farahmandian | 2 |
Ali | Rahimi | 1 |
Hassan | Abbasi | 3 |
As seen in the preceding HTML output, the rows of the table have different background colors among them. In two steps, a series of data were converted to HTML and displayed to the user.
Notes:
The first step in this design pattern does not contain any HTML code. In other words, no code related to the appearance and display is placed in the output of the first stage (including the background color and so on)
In the second stage converter, you can add header and footer pages and other sections.
For websites where each page has its design, it is usually better to use template view or transform view templates.
Consequences: Advantages
It is easy to apply changes, especially graphic changes, on the entire website.
Consequences: Disadvantages
Codes are difficult to read for non-programmers (including graphic designers).
For websites with complex graphic designs for each page, it is usually not appropriate to use this design pattern.
Applicability:
When we want to change the entire design of the pages, using this design pattern will be useful because it will only be necessary to change the XSLTs related to the HTML generation.
You can use this design pattern to implement the View section in MVC.
Related patterns:
Some of the following design patterns are not related to the Two Step View design pattern, but to implement this design pattern, checking the following design patterns will be useful:
Template view
Transform view
Model view controller
Application controller
Name:
Application controller
Classification:
Web presentation design patterns
Also known as:
---
Intent:
By using this design pattern, you can centrally manage the movement between pages and the overall flow of the program.
Motivation, Structure, Implementation, and Sample code:
Suppose a requirement is raised and, in its form, it is requested to implement the car rental process. To simplify the presentation this process has been simplified. For this requirement, we have the state diagram as follows:
Figure%2011.1.png
Figure 11.1: Car rental process
According to the Figure 11.1 diagram, the following rules are valid for a car:
When the vehicle is in On Lease status, and the return command is received, the status of the vehicle is changed to In Inventory. In this case, the rented car has been returned and added to the list of available cars. In this case, a page should be displayed to the user, and the information related to the return should be entered.
When the vehicle is in On Lease or In Inventory status, and a damage order is received, the status of the vehicle will be changed to In Repair. In this case, depending on whether the car is rented or in the parking lot, different pages are displayed to the user to enter the information related to the repair.
Receiving wrong commands in different situations will lead to displaying the error page.
There are different ways to implement this scenario. All the preceding rules can be placed in their appropriate controllers. But this method will gradually increase the complexity. A better solution is to receive all incoming requests with the help of the front controller design pattern, process it, and return the corresponding view. according to the incoming request The application controller design pattern has two main tasks:
Identifying what processing should happen.
Identifying which view should be displayed.
According to the preceding description, the following enum can be defined for different situations:
public enum State : byte
{
OnLease=1,
InInventory=2,
InRepair=3
}
According to the preceding explanation, the command design pattern can be used to implement task number 1, which is process detection. Therefore, for this section, we have the following:
public interface IDomainCommand
{
abstract public void run(NameValueCollection @params);
}
public class ReturnDetailCommand : IDomainCommand
{
public void run(NameValueCollection @params)
=> Console.WriteLine("return detail data recorded.");
}
public class IllegalActionCommand : IDomainCommand
{
public void run(NameValueCollection @params)
=> Console.WriteLine("Illegal action requested.");
}
public class LeaseDamageCommand : IDomainCommand
{
public void run(NameValueCollection @params)
=> Console.WriteLine("Lease damage data recorded.");
}
public class InventoryDamageCommand : IDomainCommand
{
public void run(NameValueCollection @params)
=> Console.WriteLine("Inventory damage data recorded.");
}
According to the preceding code, we have defined four commands for four processes. ReturnDetailCommand is responsible for processing the vehicle return. IllegalActionCommand is responsible for processing wrong requests. LeaseDamageCommand is in charge of processing requests related to the repair of the leased car, and finally, InventoryDamageCommand is in charge of processing requests related to the repair of the car in the parking lot.
Now, with commands, we need to define the relationship of each node of the provided status diagram through a structure. To define this class structure, we have considered the following:
public struct ResponseStore
{
public string Command { get; set; }
public State State { get; set; }
public Response Response { get; set; }
}
An object of the ResponseStore class determines what command has been issued (Command)? what state are we in (State)? And what response should be given (Response)? The response that is given should be able to return the request processing class and View. With these explanations, the Response class can be defined as follows:
public class Response
{
private Type domainCommand;
private string view;
public Response(Type domainCommand, string view)
{
this.domainCommand = domainCommand;
this.view = view;
}
public IDomainCommand GetDomainCommand()
=> (IDomainCommand)Activator.CreateInstance(domainCommand);
public string GetView() => view;
}
Using the Response class, you can return an object of the IDomainCommand interface implementing class. You can use the GetCommand method for this. For the sake of simplicity, exception management has not been considered in implementing this method. You can also return the View related to each command using this class. For this, the GetView method is used.
Now that the command and response-related structures are prepared, the IApplicationController interface and the CarLeasingApplicationController class can be implemented as follows.
public interface IApplicationController
{
IDomainCommand GetCommand(string command, NameValueCollection @params);
string GetView(string command, NameValueCollection @params);
}
The preceding interface specifies that each ApplicationController should be able to recognize the command and view associated with the input request. For example, the CarLeasingApplicationController class, which implements this interface, works as follows:
public class CarLeasingApplicationController : IApplicationController
{
private readonly List
public CarLeasingApplicationController()
{
AddResponse("return", State.OnLease,
typeof(ReturnDetailCommand), "return");
AddResponse("return", State.InInventory,
typeof(IllegalActionCommand), "illegalAction");
AddResponse("damage", State.OnLease,
typeof(LeaseDamageCommand), "leaseDamage");
AddResponse("damage", State.InInventory,
typeof(InventoryDamageCommand), "inventoryDamage");
}
}
As you can see, first, we implement the mentioned rules in the class constructor. For example, consider the following rule:
AddResponse("return", State.OnLease, typeof(ReturnDetailCommand), "return");
According to this rule, if the return command is issued and we are in the OnLease state, the ReturnDetailCommand is tasked with processing the request, and the return page must be displayed to the user.
private Response GetResponse(string command, State state)
=>events.FirstOrDefault(x=>x.Command==command && x.State==state).Response;
private State GetCarState(NameValueCollection @params)
=> (State)Convert.ToByte(@params["state"]);
public IDomainCommand GetCommand(string command, NameValueCollection @params)
=> GetResponse(command, GetCarState(@params)).GetDomainCommand();
In the preceding code snippet, with the help of the GetCommand method, by receiving the issued command (Command) along with the sent parameters of the request, the appropriate class for processing the request is identified:
public string GetView(string command, NameValueCollection @params)
=> GetResponse(command, GetCarState(@params)).GetView();
In the preceding piece of code, with the help of the GetView method, after receiving the issued command (Command) along with the sent parameters of the request, the appropriate View is returned:
public void AddResponse(string command, State state, Type domainCommand, string view)
{
Response response = new(domainCommand, view);
if (events.All(x => x.GetType() != domainCommand))
events.Add(new ResponseStore()
{
Command = command,
Response = response,
State = state
});
else
{
var @event = events.FirstOrDefault(x => x.Command == command);
@event.State = state;
@event.Response = response;
}
}
And finally, using the preceding method, you can save the rules in a set. So far, the application controller has been deployed. To use this structure, as mentioned in the beginning, you can benefit from the front controller design pattern. In this case, the front controller can be considered as follows:
public class FrontController
{
public void ReceiveRequest(Uri requestUrl)
{
IApplicationController controller =
GetApplicationController(requestUrl.AbsoluteUri);
NameValueCollection requestParams =
HttpUtility.ParseQueryString(requestUrl.Query);
IDomainCommand command =
controller
.GetCommand(requestUrl.Fragment.TrimStart('#'), requestParams);
command.run(requestParams);
string view = controller.GetView(
requestUrl.Fragment.TrimStart('#'), requestParams);
Console.WriteLine($"navigating to view: {view}");
}
private IApplicationController GetApplicationController(string requestUrl)
{
if (requestUrl.Contains("/leasing/")|| requestUrl.Contains("/leasing?"))
return new CarLeasingApplicationController();
else
return null;
}
}
According to the preceding code, if the request address contains the leasing value, the ApplicationController related to CarLeasing is returned. Then, based on the input request and its parameters, the values related to the command and view are identified. For example, if a request is entered with the following address:
http://abc.com/leasing?model=bmw&state=2&date=20220101#damage
Since the address contains the leasing value, the Application Controller related to CarLeasing will be selected. Then, according to the defined rules, since the damaged command has been issued and we are now in state 2, that is, InInventory, the InventoryDamageCommand should be processed. The View whose name is inventoryDamage should be returned.
Notes:
You can use the command design pattern to implement the two tasks proposed for this design pattern. You can also benefit from other methods, such as reflection instead of command.
You can use the front controller design pattern to implement the entry point to this design pattern.
If there is no connection between the application controller and the UI, the testing capability of the application controller will be improved.
The application controller can be considered an intermediate layer between the display and domain layers.
To implement more complex programs, several application controllers can be used. For smaller programs, only one application controller will be enough.
Consequences: Advantages
In complex programs, code repetition is avoided by placing the logic related to the program flow in one place, which improves maintainability.
Consequences: Disadvantages
If the flow of the program is simple, using this design pattern has no special advantage and will increase the complexity.
Applicability:
Implementing tasks such as wizards or the like in which different flows are formed based on specific rules and situations can be useful.
Related patterns:
Some of the following design patterns are not related to the Application Controller design pattern, but to implement this design pattern, checking the following design patterns will be useful:
Front controller
Command
Reflection
Conclusion
In this chapter, you got acquainted with the types of design patterns related to web displays and learned how to design and implement the view layer in a suitable way using the design patterns of this category.
In the next chapter, you will get to know the types of design patterns related to Distribution Design Patterns
Join our book's Discord space
Join the book's Discord Workspace for Latest updates, Offers, Tech happenings around the world, New Release and Sessions with the Authors:
https://discord.bpbonline.com