Introduction to Software Design Patterns and Application architecture
Design Patterns help you organize code in proven ways to solve well-understood problems. They provide access to proven methodologies for solving general problems. Choosing the right pattern leads to more maintainable code that separates unrelated tasks and functionality. Using patterns leads to better modularity, higher cohesion and lower coupling in your solution. Other big benefit of utilizing Design patterns is Reusable components which increase productivity when used across different applications with similar requirements.Gang of Four (GOF) formally introduced the Design patterns to programming community. From then, Design patterns have become more evolved and specialized through contributions of Software community esp. Martin Fowler a leading speaker and author who specializes in Enterprise application architecture, patterns and domain modeling. His book Patterns of Enterprise Application Architecture is a must read for any IT architect. Microsoft Patterns and Practices Team has indeed improving on existing patterns and pushing out more sophisticated and configurable solutions for developer community.
Recently, Microsoft patterns and practices has released Application Architecture Guide 2.0 which can be downloaded from Codeplex. This guide focuses on application design and architecture targeting for .Net Framework. This guide serves as a great reference for building almost any kind of application like service application, web app, RIA, Rich client and Mobile. Different Architectural styles like MVC, SOA, Layered, Client-Server, Message Oriented, Component based are touched upon in this guide. Relevant patterns, and practices serve as foundation for the guide.
Finally, this guide is useful to anyone who cares about application architecture and design. Any one interested in good application design will undoubtedly benefit from this well recommended guide.
If you're like me aspiring to be an IT architect someday in the future, here's collection of good books I gathered which will provide a great start on your journey to become Solution Architect :-)
There're other books as well. I've never reviewed them. So, This is my list. Ok, let's try to understand few common basic design patterns. We'll begin with Factory pattern.
Factory Pattern:
When you develop a class, you usually provide class constructors to let clients of you class instantiate it. There are times, though, when a client that needs an object does not or should not know which of several possible classes to instantiate. The FACTORY METHOD pattern lets a class developer define the interface for creating an object while retaining control of which class to instantiate.
As a example, We can consider Database Access Application Block (DAAB) to see how it implements Factory pattern.
Database db = DatabaseFactory.CreateDatabase();
The CreateDatabase() method is considered a Factory Method in that the client is isolated from knowing which concrete class to instantiate during runtime. The concrete class that will be instantiated is located in the dataConfiguration.config file. I've cut down the config file quite a bit, but you can see the concrete type to be instantiated below as Microsoft.Practices.EnterpriseLibrary.Data.Sql.SqlDatabase in the assembly Microsoft.Practices.EnterpriseLibrary.Data.
DataConfiguration.config
... Sql Server"
type="Microsoft.Practices.EnterpriseLibrary.Data.Sql.SqlDatabase,
Microsoft.Practices.EnterpriseLibrary.Data, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null" /> < SPAN>databaseTypes>< SPAN>dataConfiguration>
The Factory Method pattern requires that an operation that creates an object also isolates the client from knowing which class to instantiate. When a client requests a new object, theprecise class of the object that is created depends on the behavior of the object receiving the creation request.
Simply put, Events act as the Subject, while delegates act as Observers. Following is an example of the Observer pattern, making use of events.
public delegate void Event1Hander();
public delegate void Event2Handler(int a);
public class Subject{
public Subject(){}
public Event1Hander Event1;
public Event2Handler Event2;
public void RaiseEvent1(){
Event1Handler ev = Event1;
if (ev != null) ev();}public void RaiseEvent2()
{
Event2Handler ev = Event2; if (ev != null) ev(6);}}
public class Observer1{
public Observer1(Subject s) {
s.Event1 += new Event1Hander(HandleEvent1);
s.Event2 += new Event2Handler(HandleEvent2); }
public void HandleEvent1()
{Console.WriteLine("Observer 1 - Event 1");}
public void HandleEvent2(int a){
Console.WriteLine("Observer 1 - Event 2"); }}
The Windows Forms Button control exposes a Click event which gets raised whenever the button is clicked. Any class designed to react to this event just needs to register a delegate with that event. The Button class doesn't depend on any of the potential Observers, and each Observer only needs to know the correct type of the delegate for the event (EventHandler, in this case). Since EventHandler is a delegate type and not an interface, each Observer doesn't need to implement an extra interface. Assuming it already contains a method with a compatible signature, it only needs to register that method with the event of the Subject. Through delegates and events, the Observer pattern lets you decouple Subjects and their Observers.
Iterator Pattern
The .NET Framework uses the IEnumerable and IEnumerator interfaces to implement the Iterator pattern. The Iterator pattern lets you easily traverse a collection without exposing the inner workings of that collection. An Iterator class, an implementer of IEnumerator, is a separate class from the collection, which implements IEnumerable. The Iterator class maintains the state of the traversal (including what the current item is and whether or not there are more items to be traversed) outside of the collection itself. The algorithm for the traversal is contained in the Iterator as well. This way you can simultaneously have multiple Iterators, each traversing the same collection in wildly different ways, without adding any complexity to the collection class itself.
Decorator Pattern
The .NET Framework uses the IEnumerable and IEnumerator interfaces to implement the Iterator pattern. The Iterator pattern lets you easily traverse a collection without exposing the inner workings of that collection. An Iterator class, an implementer of IEnumerator, is a separate class from the collection, which implements IEnumerable. The Iterator class maintains the state of the traversal (including what the current item is and whether or not there are more items to be traversed) outside of the collection itself. The algorithm for the traversal is contained in the Iterator as well. This way you can simultaneously have multiple Iterators, each traversing the same collection in wildly different ways, without adding any complexity to the collection class itself.
Decorator Pattern
This ability to dynamically attach new functionality to objects transparently using composition is an example of the Decorator pattern, Given any instance of Stream, you can add the capability for buffered access by wrapping it in a BufferedStream, without changing the interface to the data. Since you are just composing objects, this can be done at run time, rather than using a technique like inheritance, which is a compile-time decision. The core functionality is defined either by an interface or by an abstract class (like Stream) from which all the Decorators derive. The Decorators themselves implement (or override) the methods in the interface (or base class) to provide the extra functionality. BufferedStream, for example, overrides Read to read from a buffer fed by the wrapped Stream, instead of reading from that Stream directly.
Adapter Pattern
One of the strengths of the .NET Framework is backward compatibility. From .NET-based code you can easily call legacy COM objects and vice versa. In order to use a COM component in your project, all you have to do is add a reference to it via the Add Reference dialog in Visual Studio .NET. Behind the scenes, Visual Studio® .NET invokes the tlbimp.exe tool to create a Runtime Callable Wrapper (RCW) class, contained in an interop assembly. Once the reference has been added (and the interop assembly has been generated for you),the COM component can be used like any other class in managed code. If you were looking at code someone else had written without seeing the list of references (and without examining metadata associated with the classes or their implementation), you would be unable to tell which classes were written in a .NET-targeted language and which were COM components.
The magic that makes this happen is contained in the RCW. COM components have different error handling mechanisms and also make use of different data types. For example, strings in the .NET Framework use the System.String class while COM might use a BSTR. When callinga COM component with a string parameter from .NET-based code, though, you can pass in a System.String just like you would to any other similar managed code method. Inside the RCW, this System.String is converted into a format that the COM component expects, like a BSTR, before the COM call is made. Similarly, a method call on a COM component typically returns an HRESULT to indicate success or failure. When a COM method call returns an HRESULT that indicates that the call failed, the RCW turns this into an exception (by default), so it can be handled like all other managed code errors. By allowing managed classes and COM components to interact despite their interface differences, RCWs are an example of the Adapter pattern.
The Adapter pattern lets you adapt one interface to another. COM doesn't understand the System.String class, so the RCW adapts it to something that it can understand. Even though you can't change how a legacy component works, you can still interact with it. Adapters are frequently used like this. The Adapter class itself wraps an Adaptee, translating all calls from the client into the appropriate format and sequence of calls. Though this sounds similar to the Decorator, there are several key differences. With a Decorator, the interfaces of the objects you're composing are the same, while the entire point of an Adapter is to allow you to change interfaces. Adapters also have a definite sequence to them; the Adaptee must be contained by the Adapter. A Decorator class doesn't need to know whether it is wrapped by 1 or 500 other classes, since the interfaces are all the same. As a result, the use of Decorators can be transparent to the application, while the use of Adapter cannot.
Adapter Pattern