文章题目:Use of design patterns in Web projects to decouple the UI and business logic implementations
Download source - 143 Kb
Introduction
As the title suggests, this is an article describing possible design pattern usage in medium/large scale web projects in order to decouple the communication between the User Interface layer and the Business/Application layer.
Design Patterns: In software engineering parlance, design patterns are standard solutions to common problems in software design. Design patterns usually describe abstract systems of interaction between classes, objects, and communication flows. So, a description of a set of interacting classes that provide a generalized solution framework to a generalized/specific design problem in a specific context can be said as a design pattern. In other words, a pattern suggests a time tested solution (involving a set of interacting classes) to a particular software design problem. It is assumed that the readers have exposure to fundamental design patterns and are acquainted with C# and the .NET environment. The two major patterns that will be used in this sample program are the Facade Pattern and the Strategy Pattern.
Background
Facade Pattern: Facade is an object oriented design pattern; essentially, an object that provides a simplified/consolidated interface to a larger piece of functionality. When designing good programs, good designers tend to attempt to avoid excess coupling between modules, and the facade pattern is a popular structural pattern for doing the same. A very good example of classical Facade pattern usage is described here.
Strategy Pattern: Strategy is also an object oriented, structural design pattern, essentially concerned with decoupling of an object and its behavior so that a single object can perform several different behaviors depending on the run-time scenarios. A lot many designers try to implement the Strategy Pattern by simple subclassing (subclass an object to achieve a different functionality). However, that is 'static' Strategy implementation as you have to create a different object in order to replace the behavior of the original object. With the actual Strategy Pattern implemented, changing the object's strategy will make it behave differently, and there is no need for providing any conditional statements to do this. Check this example here.
The code in this article will explain the usage of the above mentioned patterns in .NET based Web projects to decouple the user interface layer (developed by specialized UI developers) from the business logic layer (developed by a different set of developers who are good in implementing business logic). Let's say our program has two different business logic implementations and the implementation that will be called depends on the input provided from the UI. The independent business logic implementations are modeled using the Strategy Pattern. The UI program need not know what business implementation should actually be called. The implementation is hidden from the user interface by a Facade class object. The responsibility of the user interface ends in sending the input across to the Facade object. The Facade object, in turn, initializes the strategy object based on the user input intercepted.
Interpreting the code
The attached code contains a sample ASP.NET web client and a set of class libraries. The web client accepts a character value, which triggers a particular business process to execute; if the input is X, then the business process implemented in the class library IndependantEntity1
should be executed, else the business process encapsulated in IndependantEntity2
should be executed.
This is a seemingly easy requirement; however, it does 'model' the requirements of a medium to large scale enterprise-wide web application where different business processes need to be triggered based on inputs received from the web users. Here, a conscious attempt has been made to decouple the web client completely from the business layer class libraries; the web client has no knowledge of what business process will execute depending on the input. The only responsibility of the web client is to create a proper input message and send that message to the Facade object. The Facade object intercepts the requests, parses the requests, and acts as the client to the business layer logic algorithms implemented in the assemblies IndependantEntity1
and IndependantEntity2
(may be implemented by different teams). So we have designed the client in a manner that decouples it from the implementation details of any specific business logic or algorithm.
The interface for implementing the Strategy Pattern is called IStrategy
, and it contains only a single method called ProcessMessage
. Since an interface is like a contract, the classes which implement this interface must provide the implementation body for this method. IA1
and IA2
are two classes which implement two independent and unrelated business process functionalities for our sample project. Both these classes implement the ProcessMessage
method of the IStrategy
interface.
/*Interface definition. Interface.cs*/
using System;
namespace InterfaceProj
{
public interface IStrategy
{
bool ProcessMessage(string strXML, out string strMsg);
}
}
//-------------------------------------------------------------
//-------------------------------------------------------------
/*Interface implementation. IA1.cs*/
using System;
using InterfaceProj;
namespace IndependantEntity1
{
public class IA1: IStrategy
{
public IA1()
{
//
// TODO: Add constructor logic here
//
}
public bool ProcessMessage(string strXML,out string strMsg)
{
//parse XMl and do independant activity 1
strMsg = "Inside IA1";
return true;
}
private void DoSomeOtherIndependantActivity()
{}
}
}
The RequestFacade
class acts as the interceptor of all the web requests. This class is responsible for initializing the strategy object and calling the ProcessMessage
functionality. This class is the implementation of the Facade Pattern.
using System;
using InterfaceProj;
using IndependantEntity1;
using IndependantEntity2;
namespace RequestFacadeIntercept
{
/// <SUMMARY>
/// Summary description for RequestFacade.
/// </SUMMARY>
public class RequestFacade
{
private IStrategy objStrategy;
public RequestFacade()
{
//
// TODO: Add constructor logic here
//
}
/// <SUMMARY>
/// Process the input XML
/// Depending on the parsing instantiate the strategy object
///</SUMMARY>
public string SendRequest(string strInputXML)
{
string strMsg;
processXML(strInputXML);
//call Process
objStrategy.ProcessMessage(@"Input string extracted from XML",
out strMsg);
return strMsg;
}
private void processXML(string strInputXML)
{
//parse the xml and take appropriate decisions
if (strInputXML.Equals("X"))
objStrategy = new IA1();
else
objStrategy = new IA2();
}
}
}
The interface for implementing the Strategy Pattern is called IStrategy
, and it contains only a single method called ProcessMessage
. Since an interface is like a contract, the classes which implement this interface must provide the implementation body for this method. IA1
and IA2
are two classes which implement two independent and unrelated business process functionalities for our sample project. Both these classes implement the ProcessMessage
method of the IStrategy
interface.
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using RequestFacadeIntercept;
namespace SampleWebproject
{
.............
public class WebForm1 : System.Web.UI.Page
{
..........
................
private void Button1_Click(object sender, System.EventArgs e)
{
string strSendXML = string.Empty;
strSendXML = TextBox1.Text.ToUpper();
//populate the string with some valid input XML
//create the RequestFacade object
//and send the XML input string to the
//SendRequest method for appropriate action
RequestFacade reqfacade = new RequestFacade();
lblResponse.Text = reqfacade.SendRequest(strSendXML);
//the web ui developer need to just create the
//XML based on pre supplied (out of scope of this demo)
//and call SendRequest
}
}
}
Points of Interest
The use of design patterns is very common in any medium to large scale project. This sample just illustrates the use of Strategy and Facade patterns in Web projects. And the fact that the web client can be decoupled from the business logic implementation so easily by use of design patterns should encourage more use of such patterns in projects during the design phase. This will also free up any sort of dependency between UI designers and business logic developers; specialized people can keep themselves busy doing their own stuff without bothering about how to communicate with each others' artifacts. Such loose coupling between the UI and the business logic also allows the business logic to be modified without the knowledge of the UI as long as the input message intercepted by the Facade layer remains the same. The only code which needs to be altered for any future changes is the Facade object. So, application maintenance and scalability issues are also addressed by the use of such patterns.
This is just a sample. There are other ways to achieve the same objectives. So keep exploring design patterns.
园子里有不少人在写设计模式的文章,我看过吕震宇老师和李会军老师的这方面的一系列文章,觉得写得很精彩,虽然本人尚没有非常深刻得理解设计模式,但是对于刚入门的我也是受益匪浅啊!