This article was updated on 10/10/2016.
.NET Design Patterns…. yes, there are several books and resources written on this topic. When it comes to Software Development, Design Patterns promotes constancy across the code base and allows us to develop better maintainable software.
There are many Design Patterns in Software Development. Some of these patterns are very popular. It is almost true to say that most patterns can be embraced irrespective of the programming language we choose. We will be seeing how to use some coding Patterns in C#.
Are you keeping up with new developer technologies? Advance your IT career with our Free Developer magazines covering C#, Patterns, .NET Core, MVC, Azure, Angular, React, and more. Subscribe to this magazine for FREE and download all previous, current and upcoming editions.
Based on the type of application, we may use one or more Patterns. Sometimes we may mix and match them as well. It is very important to consider that we primarily want to use these patterns as effective communication tools. This may not be obvious at this stage. However during this article, we will look at how software patterns are utilised in various applications.
In this article we will not just focus on a set of Design Patterns. We well take a fresh view of some of the existing onesand see how we can go about using them in real world dilemmas and concerns.
.NET Design Patterns - Bit of a background
It is a fact that some developers hate Design Patterns. This mainly because of analysing, agreeing and implementing a particular Pattern can be a headache. I’m pretty sure we have all come across situations where developers spend countless hours, if not days, discussing the type of pattern to use. Not to mention, the best approach and the way to go about implementing it. This is a very poor way to develop software.
This dilemma is often caused by thinking that their code can fit into a set of Design Patterns. This is an incredibly hard thing to do. But if we think these Patterns are a set of tools which allows us to make good decisions and can be used as an effective communication tool; then we are approaching it in the right way.
This article mainly focuses on .NET Design Patterns using C# as the programming language. Some Patterns may be applied to non .NET based programming languages as well. Repeating what I said earlier, most patterns can be embraced irrespective of the programming language we choose.
Abstract Factory Pattern
Wikipedia definition: “The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes.”
While this definition is true, the real usage of this pattern can be varying. It can be based on real life concerns and problems people may have. In its simplest form, we would create instances with related objects without having to specify their concrete implementations. Please refer to the following example:
public class Book
{
public string Title { get; set; }
public int Pages { get; set; }
public override string ToString()
{
return string.Format("Book {0} - {1}", Title, Pages);
}
}
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine(CreateInstance("ConsoleApplication1.Book", new Dictionary
As per the above example, creation of instances are delegated to a routine called CreateInstances().
This routine takes a class name and the property values as arguments.
At the first glance, this seems like a lot of code just to create an instance and add some values to its properties. But the approach becomes very powerful when we want to dynamically create instances based on parameters. For example, creating instances at runtime based on User Inputs. This is also very centric to Dependency Injection (DI). The above example just demoes the fundamental of this pattern. But the best way to demonstrate Abstract Factory pattern is to take a look at some real world examples. It would be redundant to introduce something already out there. Therefore if you are interested, please see this Stack Overflow question, which has some great information.
Additional Note: Activator.CreateInstance is not centric to Abstract Factory Pattern. It just allows us to create instances in a convenient way based on the type parameter. In some cases we would just create instances by new’ing up (i.e new Book()) and still use the Abstract Factory Pattern. It all depends on the use case and their various applications.
Cascade Pattern
I’m sure we often see code patterns like the following:
public class MailManager
{
public void To(string address) { Console.WriteLine("To");}
public void From(string address) { Console.WriteLine("From"); }
public void Subject(string subject) { Console.WriteLine("Subject"); }
public void Body(string body) { Console.WriteLine("Body"); }
public void Send() { Console.WriteLine("Sent!"); }
}
public class Program
{
public static void Main(string[] args)
{
var mailManager = new MailManager();
mailManager.From("alan@developer.com");
mailManager.To("jonsmith@developer.com");
mailManager.Subject("Code sample");
mailManager.Body("This is an the email body!");
mailManager.Send();
}
}
This is a pretty trivial code sample. But let’s concentrate on the client of the MailManager class, which is the class Program. If we look at this class, it creates an instance of MailManager and invokes routines such as .To(), .From(), .Body() .Send() etc.
If we take a good look at the code, there are a couple of issues in writing code like we just saw.
a. Notice the variable “mailManager”. It has been repeated number of times. So we feel somewhat awkward writing redundant writing code.
b. What if there is another mail we want to send out? Should we create a new instance of MailManager or should we reuse the existing “mailManager” instance? The reason we have these questions in the first place is that the API (Application Programming Interface) is not clear to the consumer.
Let’s look at a better way to represent this code.
First, we make a small change to the MailManager class as shown here. We modify the code so we could return the current instance of the MailManager instead of the return type void.
Notce that the Send() method does not return the MailManager. I will explain why we did this is in the next section.
Modified code is shown here.
public class Mailmanager
{
public MailManager To(string address) { Console.WriteLine("To"); return this; }
public MailManager From(string address) { Console.WriteLine("From"); return this; }
public MailManager Subject(string subject) { Console.WriteLine("Subject"); return this;}
public MailManager Body(string body) { Console.WriteLine("Body"); return this; }
public void Send() { Console.WriteLine("Sent!"); }
}
In order to consume the new MailManager implementation, we will modify the Program as below.
public static void Main(string[] args)
{
new MailManager()
.From("alan@developer.com")
.To("jonsmith@developer.com")
.Subject("Code sample")
.Body("This is an the email body!")
.Send();
}
The duplication and the verbosity of the code have been removed. We have also introduced a nice fluent style API. We refer to this as the Cascade pattern. You probably have seen this pattern in many popular frameworks such as FluentValidation. One of my favourites is the NBuilder.
Builder.CreateNew().With(x => x.Title = "some title").Build();
Cascade-Lambda pattern
This is where we start to add some flavour to the Cascade Pattern. Let’s extend this example a bit more. Based on the previous example, here is the code we ended up writing.
new MailManager()
.From("alan@developer.com")
.To("jonsmith@developer.com")
.Subject("Code sample")
.Body("This is an the email body!")
.Send();
Notice that the Send() method is invoked from an instance of the MailManager. It is the last routine of methods chain. Therefore it does not require returning an instance. This also means the API implicitly indicates that if we want send another mail, we will have to create a new MailManager instance. However it is not explicitly clear to the user what we should do after the call to .Send().
This is where we can take the advantage of lambda expressions and make the intention explicit to the consumer of this API.
First we convert the Send() method to a Static method and change its signature to accept an Action delegate. This delegate takes the MailManager as a parameter. We invoke this action within the Send() method as shown here:
public class MailManager
{
public MailManager To(string address) { Console.WriteLine("To"); return this; }
public MailManager From(string address) { Console.WriteLine("From"); return this; }
public MailManager Subject(string subject) { Console.WriteLine("Subject"); return this;
}
public MailManager Body(string body) { Console.WriteLine("Body"); return this; }
public static void Send(Action action) { action(new MailManager()); Console.WriteLine("Sent!"); }
In order to consume the MailManager class, we can change the Program as seen here:
Mailmanager.Send((mail) => mail
.From("alan@developer.com")
.To("jonsmith@developer.com")
.Subject("Code sample")
.Body("This is an the email body!"));
As we see in the code sample, the action specified by the delegate as an argument to the Send() method clearly indicates that the action is related to constructing a mail. Hence it can be sent out by calling the Send() method. This approach is much more elegant as it removes the confusions around the Send() method, which I described earlier.
Pluggable pattern
The best way to describe the pluggable behaviour is to use an example. The following code sample calculates the total of a given array of numbers.
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine(GetTotal(new [] {1, 2, 3, 4, 5, 6}));
Console.Read();
}
public static int GetTotal(int[] numbers)
{
int total = 0;
foreach (int n in numbers)
{
total += n;
}
return total;
}
}
Let’s say we have a new requirement. Although we do not want to change the GetTotal() method, but we would also like to calculate only even numbers. Most of us would add another method, say GetEvenTotalNumbers as shown here.
public class Program
{
public static int GetTotal(int[] numbers)
{
int total = 0;
foreach (int n in numbers)
{
total += n;
}
return total;
}
public static int GetTotalEvenNumbers(int[] numbers)
{
int total = 0;
foreach (int n in numbers)
{
if (n%2 == 0)
{
total += n;
}
}
return total;
}
public static void Main(string[] args)
{
Console.WriteLine(GetTotal(new [] {1, 2, 3, 4, 5, 6}));
Console.WriteLine(GetTotalEvenNumbers(new[] { 1, 2, 3, 4, 5, 6 }));
Console.Read();
}
}
We just copied/pasted the existing function and added the only condition that requires calculating even numbers. How easy is that! Assuming there is another requirement to calculate the total of odd numbers, it is again as simple as copying/pasting one of the earlier methods, and modifying it slightly to calculate odd numbers.
public static int GetTotalOddNumbers(int[] numbers)
{
int total = 0;
foreach (int n in numbers)
{
if (n % 2 != 0)
{
total += n;
}
}
return total;
}
At this stage you probably realize that this is not the approach we should take to write software. It is pretty much copy paste unmaintainable code. Why is it unmaintainable? Let’s say if we have to make a change to the way we calculate the total. This means we would have to make changes in 3 different methods.
If we carefully analyse all 3 methods, they are very similar in terms of their implementation. Only difference is the if condition.
In order to remove the code duplication we can introduce the Pluggable Behaviour.
We can externalize the difference and inject it into a method. This way the consumer of the API has control over what has been passed into the method. This is called the Pluggable Behaviour.
public class Program
{
public static int GetTotal(int[] numbers, Predicate selector) { int total = 0; foreach (int n in numbers) { if (selector(n)) { total += n; } } return total; } public static void Main(string[] args) { Console.WriteLine(GetTotal(new [] {1, 2, 3, 4, 5, 6}, i => true)); Console.WriteLine(GetTotal(new[] { 1, 2, 3, 4, 5, 6 }, i => i % 2 == 0)); Console.WriteLine(GetTotal(new[] { 1, 2, 3, 4, 5, 6 }, i => i % 2 != 0)); Console.Read(); } }
As we see in the above example, a Predictate has been injected to the method. This allows us to externalize the selection criteria. The code duplication has been removed, and we have much more maintainable code.
In addition to this, let’s say we were to extend the behaviour of the selector. For instance, the selection is based on multiple parameters. For this, we can utilize a Func delegate. You can specify multiple parameters to the selector and return the result you desire. For more information on how to use Func delegate please refer to Func.
Execute Around Pattern with Lambda Expressions
This pattern allows us to execute a block of code using lambda expression. Now that sounds very simple and that’s what lambda expressions do. However this pattern is about using lambda expressions and implements a coding style, which will enhance one of the existing popular Design Patterns. Let’s see an example.
Let’s say we want to clean-up resources in an object. We would write code similar to the following:
public class Database
{
public Database()
{
Debug.WriteLine("Database Created..");
}
public void Query1()
{
Debug.WriteLine("Query1..");
}
public void Query2()
{
Debug.WriteLine("Query2..");
}
~Database()
{
Debug.WriteLine("Cleaned-Up");
}
}
public class Program
{
public static void Main(string[] args)
{
var db = new Database();
db.Query1();
db.Query2();
}
}
The output of this program would be..
Database Created..
Query1..
Query2..
Cleaned Up!
Note that the Finalizer/Destructor implicitly gets invoked and it will clean-up the resources. The problem with the above code is that we don’t have control over when the Finalizer gets invoked.
Let’s see the same code in a for loop and execute it a couple of times:
public class Program
{
public static void Main(string[] args)
{
for (int i = 0; i < 4; i++)
{
var db = new Database();
db.Query1();
db.Query2();
}
}
}
The Program would produce an output like the following.
Database Created..
Query1..
Query2..
Database Created..
Query1..
Query2..
Database Created..
Query1..
Query2..
Database Created..
Query1..
Query2..
Cleaned Up!
Cleaned Up!
Cleaned Up!
Cleaned Up!
All clean up operations for each DB creation happened at the end of the loop!
This may not be ideal if we want to release the resources explicitly so they don’t live in the managed heap too long before being Garbage Collected. In a real world example, there can be so many objects having a large object graph, trying to create database connections and timing out. The obvious solution is to clean-up the resources explicitly and as quickly as possible.
Let’s introduce a Cleanup() method as seen here:
public class Database
{
public Database()
{
Debug.WriteLine("Database Created..");
}
public void Query1()
{
Debug.WriteLine("Query1..");
}
public void Query2()
{
Debug.WriteLine("Query2..");
}
public void Cleanup()
{
Debug.WriteLine("Cleaned Up!");
}
~Database()
{
Debug.WriteLine("Cleaned Up!");
}
}
public class Program
{
public static void Main(string[] args)
{
for (int i = 0; i < 4; i++)
{
var db = new Database();
db.Query1();
db.Query2();
db.Cleanup();
}
}
}
Database Created..
Query1..
Query2..
Cleaned Up!
Database Created..
Query1..
Query2..
Cleaned Up!
Database Created..
Query1..
Query2..
Cleaned Up!
Database Created..
Query1..
Query2..
Cleaned Up!
Cleaned Up!
Cleaned Up!
Cleaned Up!
Cleaned Up!
Note that we have not removed the Finalizer yet. For each database creation Cleanup() will perform explicitly. As we saw in the first for loop example, at the end of the loop, the resources will be garbage collected.
One of the problems with this approach is that if there is an exception in one of the Query operations, the clean-up operation would never get called.
As many of us do, we wrap the query operations in a try{} block and a finally {} block and perform the clean-up operation. Additionally we catch{} the exception and do something, but I have ignored that for code brevity.
public class Program
{
public static void Main(string[] args)
{
for (int i = 0; i < 4; i++)
{
var db = new Database();
try
{
db.Query1();
db.Query2();
}
finally
{
db.Cleanup();
}
}
}
}
Technically this solves the problem. As the clean-up operation always gets invoked regardless of whether there is an exception or not.
However this approach still has some other issues. For instance, each and every time when we instantiate the Db and invoke query operations, as developers we have to remember to include it in the try{} and finally{} blocks. To make things worse, in more complex situations, we can even introduce bugs without knowing which operation to call etc.
So how do we tackle this situation?
This is where most of us would use the well-known Dispose Pattern. With the Dispose Pattern try{} and finally{} are no longer required. The IDisposable.Dispose() method cleans-up the resources at the end of the operations. This includes any exception scenarios during query operations.
public class Database : IDisposable
{
//More code..
public void Dispose()
{
Cleanup();
GC.SuppressFinalize(this);
}
}
public class Program
{
public static void Main(string[] args)
{
for (int i = 0; i < 4; i++)
{
using (var db = new Database())
{
db.Query1();
db.Query2();
}
}
}
This is definitely a much better way to write the code. The using block abstracts away the dispose of the object. It guarantees that the clean-up will occur using Dispose() routine. Most of us would settle with this approach. You will see this pattern used in many applications.
But if we really look closely there is still a problem with the using pattern itself. Technically it will do right thing by explicitly cleaning-up resources. But there is no guarantee that the client of the API would use the using block to clean-up-up the resources. For example, anyone can still write the following code:
var db = new Database();
db.Query1();
db.Query2();
For resource intensive applications, if this code has been committed without being noticed, this can have an adverse effect on the application. So we are back to square one. As we have noticed, there is no immediate dispose or clean-up operation that takes place.
A chance of missing the Dispose() method is a serious problem. Not to mention we are also presented with a new challenge of making sure we implement the Dispose method/logic correctly. Not everyone knows how to implement the Dispose method/logic correctly. Most would resort for some other resources such as blogs/articles. This is all unnecessary trouble to go through.
So in order to address these issues, it would be ideal if we can change the API in such a way that developers cannot make mistakes.
This is where we can use Lambda Expressions to resolve these issues. In order to implement the Execute Around Pattern with Lambda Expressions we will modify the code with the following:
public class Database
{
private Database()
{
Debug.WriteLine("Database Created..");
}
public void Query1()
{
Debug.WriteLine("Query1..");
}
public void Query2()
{
Debug.WriteLine("Query2..");
}
private void Cleanup()
{
Debug.WriteLine("Cleaned Up!");
}
public static void Create(Action execution) { var db = new Database(); try { execution(db); } finally { db.Cleanup(); } } }
There are few interesting things happening here. IDisposable implementation has been removed. The constructor of this class becomes private. So the design has been enforced in such a way that the user cannot directly instantiate the Database instance. Similarly the Cleanup() method is also private. There is a new Create() method, which takes an Action delegate (which accepts an instance of the database) as a parameter. The implementation of this method would execute the action specified by the Action parameter. Importantly, the execution of the action has been wrapped in a try{} finally{} block, allowing the clean-up operation as we saw earlier.
Here is how the client/user consumes this API
public class Program
{
public static void Main(string[] args)
{
Database.Create(database =>
{
database.Query1();
database.Query2();
});
}
}
The main difference from the previous approach is that now we are abstracting the clean-up operation from the client/user and instead are guiding the user to use a specific API. This approach becomes very natural as all boilerplate code has been abstracted away from the client. This way it is hard to imagine that the developer would make a mistake.
More Real World Applications of Execute Around Method Pattern with Lambda Expression
Obviously this pattern is not limited to managing resources of a database. It has so many other potentials. Here are some of its applications.
· In Transactional code where we create a transaction and check whether the transaction is completed, then commit or rollback when required.
· If we have heavy external resources that we want to dispose as quickly as possible without having to wait for the .NET Garbage collection.
· To get around with some framework limitations – more on this below. This is quite interesting. Please see below.
Tackling Framework Limitations
I’m sure most of you are familiar with Unit Testing. I’m a huge fan of Unit Testing myself. In .NET platform, if you have used MSTest framework, I’m sure you have seen the ExpectedException attribute. There is a limitation on the usage of this attribute where we cannot specify the exact call that throws an exception during the test execution.
For example, see the test here.
[TestClass]
public class UnitTest1
{
[TestMethod][ExpectedException(typeof(Exception))]
public void SomeTestMethodThrowsException()
{
var sut = new SystemUnderTest("some param");
sut.SomeMethod();
}
}
This code demoes a typical implementation of an ExpectedException attribute. Note that we expect sut.SomeMethod() would throw an exception.
Here is how the SUT (System Under Test ) would look like. Note that I have removed the detailed implementation for code brevity.
public class SystemUnderTest
{
public SystemUnderTest(string param)
{
}
public void SomeMethod()
{
//more code
//throws exception
}
}
During test execution, if there is an exception being thrown, it will be caught and the test would succeed. However the test would not know exactly where the exception has been thrown. For example, it could be during the creation of the SytemUnderTest.
We can use the Execute Around Method Pattern with Lambda Expression to address this limitation. This is by creating a helper method, which accepts an Action parameter as delegate.
public static class ExceptionAssert
{
public static T Throws(Action action) where T : Exception { try { action(); } catch (T ex) { return ex; } Assert.Fail("Expected exception of type {0}.", typeof(T)); return null; } }
Now the text method can be invoked as seen here.
[TestMethod]
public void SomeTestMethodThrowsException()
{
var sut = new SystemUnderTest("some param");
ExceptionAssert.Throws(() => sut.SomeMethod()); }
The above ExceptionAssert.Throws() can be used to explicitly invoke the method that throws the exception.
A separate note…
We would not have this limitation in some of the other Unit Testing framework such as NUnit, xUnit. These frameworks already have built-in helper methods (implemented using this pattern) to target the exact operation that cause exception.
For example xUnit.NET has
public static T Throws(Assert.ThrowsDelegate testCode) where T : Exception
Summary
In this article we looked at various .NET Design Patterns in C#. Design Patterns are good but they only become effective if we can use them correctly. We would like to think Design Patterns as a set of tools which allow us to make better decisions on the code base. We would also like to treat them as communication tools so we can improve the communication around the code base.
We have looked at the Abstract Factory Pattern and Cascade Pattern. We have also looked at applying a slightly different approach to the existing Design Patterns using lambda expressions. This includes the Cascade-Lambda Pattern, Pluggable Pattern, and finally the Execute Around Pattern with Lambda Expressions. Throughout this article we saw that Lambda Expressions are a great way to enhance the power of some of the well-known Software Patterns.
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Raj Aththanayake is a Microsoft ASP.NET Web Developer specializing in Agile Development practices such Test Driven Development (TDD) and Unit Testing. He is also passionate in technologies such as ASP.NET MVC. He regularly presents at community user groups and conferences. Raj also writes articles in his blog
http://blog.rajsoftware.com. You can follow Raj on twitter @raj_kba