Solid OO design patterns with C#
This workshop will introduce delegates to the wonderful world of object-oriented design patterns. Once understood, design patterns allow the leveraging of proven solutions to common re-occurring problems. Probably the most important aspect to design patterns is that they provide a common vocabulary to describe a system. No longer will teams of developers need to discuss lines of code, but instead will be able to describe the system as a series of patterns, leading to accurate and efficient communication. As part of this process delegates will obtain key insights in how to design good object-oriented systems and how to test them. The original ‘Gang of Four’ design patterns were documented prior to .NET, in this course the implementation of these patterns is brought up to date using the latest versions of C# and the .NET Framework.
To attend this course developers should have at least 6 months C# experience.
Why Design Patterns?
This module discusses the reasons why you should study design patterns. Design patterns offer the ability to reuse solutions not just code. By reusing already established designs, you get a head start on problems and avoid gotchas; you benefit by learning from the experience of others; you do not have to reinvent solutions for commonly recurring problems.
Design patterns establish a common terminology, allowing developers to use a common vocabulary and share a common viewpoint of the problem, and provide a common point of reference during the analysis and design phase of a project.
The course will use UML as a means to communicate pattern intent, and this section will introduce key UML concepts.
Strategy and Template Patterns
What we can be 100% sure of with software is that constantly needs to evolve. What we also know is every time we change existing working code there is a risk that we will break it. What we need is an approach that will allow the software to evolve without having to modify existing working code. The strategy and template patterns allow us to build solutions that can evolve without the risk of effecting existing well tested code.
Some solutions require the use of a single object instance across the whole solution, for example naming services, cached objects. This chapter will introduce the singleton pattern as a solution, along with variations for thread safety, and other varieties of single instance based on thread affinity.
The ability to notify interested entities of changes to an object state is a fundamental requirement of most object-oriented solutions. There are many ways to do this but there is a danger that we will build a tightly coupled system, we prefer to build a loosely coupled system. The typical way of implementing the observer pattern is to use interfaces, but we will show that delegates and events are a far more flexible and efficient way of implementing the pattern on the .NET framework.
There are occasions when you want to decouple the knowledge of which type to create from the client code. This is essential for effective unit testing. There are a variety of creation pattern that will allow you do this by encapsulating the necessary knowledge of how to create the object thus allowing the actual implementation used to vary. In this section we will look at the Factory, Builder and Prototype patterns.
Iterator, Composite and Visitor Patterns
There is often a need to access every object inside an object hierarchy: user interface control objects, documents, business entities, file systems, etc. The iterator pattern provides a standard means to achieve this, .NET provides a standard implementation of this, further the C# language simplifies the implementation further through language extensions. The visitor pattern gives us the ability to layer behaviour onto the hierarchy without the need to change the underlying implementation of the hierarchy, continuing the theme of closed for modification, open for extension.
One of the key design pattern goals is to write code that is closed for modification and open to extension, this pattern will show that an objects behaviour and responsibilities can be extended at runtime, as opposed to design time using inheritance. This will allow us to combine a variety of behaviours far more efficiently that normal inheritance. Examples of decorators in the framework are BufferedStream, SynchronizationWrappers and XmlValidatingReaders.
The command pattern allows us to encapsulate invocation, allowing the invoker to be decoupled from the client and the recipient, this enables us to build a variety of different invokers to deliver custom thread pooling, and invocation logging to build fault tolerant solutions. We continue to extend the command pattern to not only encapsulate forward invocation but also undo invocation, allowing us to build a complex undo sequence through a series of simple undo commands.
In many cases object behaviour will depend on the state an object is in, we typically model the internals of objects through the use of a finite state machine. This pattern provides a means to map a finite state machine into a series of classes where each class represents a different state, thus providing different behaviours. This approach allows us to add new states and transitions without affecting existing code, continuing the theme of closed for modification, open for extension.
Prior to co-founding Rock Solid Knowledge, Andy cut his teeth working in various start-ups, programming on a host of platforms, and finally working for a company acquired by Cisco in 1997. After working for Cisco for a few years, the pull of the start-up world was too much to resist, and he now spends his time working on RSK’s kiosk-based solutions on Windows Embedded with .NET, alongside consulting and teaching for a diverse range of clients. Andy is the co-author of Pro Asynchronous Programming with .NET, published by Apress.
Richard is one of the founders of Rock Solid Knowledge. He has been working in the software industry for over 20 years – starting with mainframes, through the early years of client/server, to today’s service-oriented world. He has spent much of his professional life working on large distributed systems, including being the middle-tier architect on the UK national police systems. He is the co-author of Pro Async Programming with .NET, a Microsoft Integration MVP, and a regular speaker at various technical conferences.