Introduction
Well, we all write code every day and many a times we feel we should have a better way to write code. Most probably a code that is easily maintainable and easily extendable. When we write code, we end up writing the code that has tight coupling, so if any new requirement comes in; we have to modify the existing code, this way our code is not closed for modification. One basic line has to be remembered “Code should be closed for modification but open for extension”. So keeping in mind this famous line, I will be writing a small application that will tell what need to be done to get ready for modification and allow extension without changing code. I would be trying to take the famous “MVC” approach to separate the different layers so the reader understands how it can benefit in day to day coding.
Background
Usually when we get requirement we start writing code without looking much on what if new requirement comes in or new customer want something different.
Using the Code
Requirement
Here in I am going to write a small application that shows the benefits of using object oriented concepts. We have got one requirement that says, we need to display employee data based on some department filtration. There is a requirement that this data can be shown in grid and a combo box can be used to filter the record. Also there should be another listbox control that displays only the First column of the grid i.e. in our case Employee Name. So on change of combo box item the grid loads with filtered Employee data and when row of grid selected it load the listbox with employee name belonging to department id.
Solution @ first sight
Well no big deal, let’s create a window application and create a data layer that has the data to load the combo box and also has collection of data to be displayed in the grid based on filter criteria specified by combo box. Drag a combo box, grid and a list box on window form. Load the combo box with data and on SelectedIndexChanged event of combo box load the filtered data in the grid.
private void cmbEntity_SelectedIndexChanged(object sender, EventArgs e)
{
if(null != cmbEntity.SelectedItem){
int val = Convert.ToInt16(cmbEntity.SelectedItem);
List<Entity> entities = objEntData.GetAllData(val);
dgEntityView.DataSource = entities;
}
void dgEntityView_RowEnter(object sender, DataGridViewCellEventArgs e)
{
lstBoxEntity.Items.Clear();
foreach (EmployeeEntity item in entities)
{
lstBoxEntity.Items.Add(item.EmployeeName);
}
}
So here you can see when event triggers we load the data based on combo selected item and load the grid and when grid selected row event fire we load the Employee Name in list box.
Tight coupling [not a good sign for extension]
Problem with this approach:
After design is freezes, another customer came in and asks for some new view in web instead of window. Also this customer wants data to be displayed in Chart instead of grid. So again no issue let’s create another web application. Well, definitely there will be lot of redundant code and also maintaining these multiple application will be nightmare [keeping in mind the big enterprise application]. So this will continue with new Customer asking for this feature in WPF and so on.
Well we have to think a better design
The design should be such that we can reduce the cost on maintainability and design should be easily portable to other application type.
Better Approach
Looking at the requirement, it looks it is view that is going to be changed [Could be a webform/WPF page etc.]. So let’s have a design that can be used for these entire requirements.
Our object should be loosely coupled or in other sense there should be separation of one layer from another for future extension and better maintainability.
Do we have any pattern that fit in our requirements?
MVC - Model View Controller
Model
Implement Observer pattern/ notify all subscribers with changed data or with changed states
Model notify the views subscribed to get notification
View
Display to user, Deal with User Action. [Click button/Select item from combo box etc.
Controller
Takes user input and ask Model to act on view request. Change State/Return Data.
Controller can also ask view to change based on view input [like enable/disable controls.]
The view only worried about presentation, the controller worried about translating user input to actions on the model. Model responsible to notify all the subscribers with changed data.
What changes need to be done in Code
Let’s create a class library project named MVC and add new folders named Controller, Data, Interface, model and RequestHandlres.
Data
Add our class that contains the data for demo purpose. Here I have created EmployeeEntity and Department that has certain properties. Another class named EntityDataRepositery creates the collection to be used in demo.
Interface:
public interface IDataObserver
{
void Update(object data);
string SubscriptionKey { get;}
string ObserverKey { get; }
}
public interface IModel
{
void GetData(int id,string key);
void RegisterObserver(IDataObserver dataObserver, string key);
void RemoveObserver(IDataObserver dataObserver);
}
public interface IController
{
void GetEntity(int entityId, string key);
}
Model
DataModel class is responsible of implementing IModel interface and to notify the registered observer whenever any data is requested.
public sealed class DataModel : IModel
This class has to implement IModel interface:
public void RegisterObserver(IDataObserver dataObserver, string key)
{
if (!dataObservers.Contains(dataObserver))
{
dataObservers.Add(dataObserver);
}
}
void Notify(int id, string key)
{
foreach (var item in dataObservers)
{
if (((IDataObserver)(item)).ObserverKey == key)
((IDataObserver)(item)).Update(dataObject.GetAllData(id));
}
}
Controller
EntityController class implements IController interface. It has dataModel object to be used when view request some data and Controller intercept the request and send it to Model to notify the registered observer.
public class EntityController : IController
{
IModel dataModel;
public EntityController(IModel model)
{
this.dataModel = model;
}
public void GetEntity(int entityId, string key)
{
dataModel.GetData(entityId,key);
}
}
ReqHandler
It has BaseReqH class, this class is used to have a reference of Model and Controller to be accessed by child classes. This class has a special purpose to avoid creating object of model/controller by sub classes. Any class that derives from BaseReqH doesn’t need to create these instances.
public BaseReqH()
{
model = model ?? new DataModel();
controller = controller ?? new EntityController(model);
}
Now the fun begins after all hard work in base classes.
So how does this help in creating different views without affecting existing base classes or by extending base classes?
Let’s create a new window application and on window form drag and drop a combo box, datagrid and Listbox.
We need to load the combo box with Departments and DataGrid should be loaded with selected department employee only. Also when user select Datagrid row the ListBox should be loaded with respective employee name belonging to selected department id taken from Datagrid cell.
To achieve this DatagridReqH should be subscribed to ComboReqH and ListBoxReqH should be subscribed to controller DatagridReqH. action invokes the model to notify all those subscriber who has matching key.
- When user select department on combo, controller pass the departmentId and subscription key.
void cmb_SelectedValueChanged(object sender, EventArgs e)
{
controller.GetEntity(Convert.ToInt16(cmb.SelectedValue), this.SubscriptionKey);
}
- DatagridReaH is the observer of ComboReqH and also implement IDataObserver. It register with model with the Observer Key
model.RegisterObserver(this, ObserverKey);
- EntityController calls datamodel and passed the required data.
public void GetEntity(int entityId, string key)
{
dataModel.GetData(entityId, key);
}
- DataModel getData calls Notify method and check who are the subscribers to update and call all subscribers Update method
void Notify(int id, string key)
{
foreach (var item in dataObservers)
{
if (((IDataObserver)(item)).ObserverKey == key)
((IDataObserver)(item)).Update(dataObject.GetAllData(id));
}
}
- The DataGridReqH is one of the subscriber its update method get called and load the datagrid
public void Update(object data)
{
dgView.DataSource = data;
}
- Now you need to instantiate the different request handler in Window form constructor, or in web form constructor or in MainWindow WPF constructor
In window application constructor instantiate below Reqest Handlers
BaseReqH bs = new BaseReqH();
ComboReqH creq = new ComboReqH(cmbEntity);
DataGridReqH dreq = new DataGridReqH(dgEntityView);
ListBoxReqH lreq = new ListBoxReqH(lstBoxEntity);
Run the application and you see the desired functionality achieved using writing few request handlers and MVC approach. Just to add don’t forget the role of Observer Pattern in this application.
See once we have written our MVC framework, how easy to build UI. Let assume now we need to show data in a chart instead of grid whenever department id changed and that too in ASP.NET application.
- Create a new web application, drag and drop dropdownlist and chart on webform.
- Chart should be derived from WebReqH and also a subscriber to combobox.
- Whenever departmentid changes, the request go to controller and controller asks the model to update the matching subscriber i.e. Chart in our case.
- Instantiate the required request handlers in web form page load.
I hope you have enjoyed reading this article, if you liked it please don’t forget to rate this and leave your comment.
Happy Programming J