Code & Test Smarter with Design Patterns
This course has been retired. Please view currently available Object Orientation Training Courses.
Design Patterns (1 topic)
- 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. Design patterns 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 module will introduce key UML concepts.
Singleton Pattern (1 topic)
- Some solutions require the use of a single object instance across the whole solution, for example, naming services and cached objects. This module will introduce the Singleton pattern as a solution, along with variations for thread safety, and other varieties of single instance based on thread affinity.
Template and Strategy Patterns (1 topic)
- What we can be 100% sure of with software is that it constantly needs to evolve. What we also know is that 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 Template and Strategy patterns allow us to build solutions that can evolve without the risk of affecting existing, well tested code.
Creation Patterns (1 topic)
- 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 patterns that will allow you do this, by encapsulating the necessary knowledge of how to create the object and thus allowing the actual implementation used to vary. In this module, we will look at the Factory, Builder and Prototype patterns.
Observer Pattern (1 topic)
- The ability to notify interested entities of changes to an object's state is a fundamental requirement of most object-oriented solutions. There are many ways to do this, but there is always a danger that we will build tightly coupled systems, whereas we prefer to build loosely coupled systems. 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 when using the .NET framework.
Iterator, Composite and Visitor Patterns (1 topic)
- There is often a need to access every object in an object hierarchy, such as a user interface's control objects, documents, business entities, file systems. etc. The Iterator pattern provides a standard means to achieve this and .NET provides a standard implementation of this. Also, 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, this module also looks at the Open/Closed Principle (OCP), the principle of open for extensibility but closed for modicfication.
Decorator Pattern (1 topic)
- One of the key design pattern goals is to write code that is open for extensibility but closed for modification. This pattern will show that an object's 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 than normal inheritance. Examples of decorators in the .NET Framework include BufferedStream, XmlValidatingReader and the synchronisation wrappers.
Command Pattern (1 topic)
- 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.
State Pattern (1 topic)
- In many cases, object behaviour will depend on the state an object is in and we typically model the internals of objects through the use of finite state machine. This pattern provides a means to map a finite state machine onto a series of classes where each class represents a different state, thereby providing different behaviours. This approach allows us to add new states and transitions without affecting existing code, continuing the theme of open for extensibility but closed for modification.
Test-Driven Development and Unit Testing (1 topic)
- Unit testing is now considered by most developers to be an essential part of writing high quality software and it is now compulsory in many organisations. Test-driven development (TDD) is the next logical progression from unit testing, which delivers demonstrably higher levels of code quality than simple unit testing. This module takes a detailed look at unit testing and TDD, from the real-world benefits to how to craft good unit tests (and how to avoid writing bad ones). It also explains the AAA pattern, the red-green-refactor approach to TDD, the continuous test runner and how to manage large suites of unit tests so that the right tests can be run frequently and quickly.
Data-Driven Unit Testing and Code Coverage (1 topic)
- Developers who practice unit testing and TDD often find themselves needing to test a behaviour in a number of different ways. While this can be achieved by writing a number of very similar unit tests, a better way is to create a data-driven unit test, which allows a single test to execute many times with different test values. This module examines how to create and configure data-driven unit tests. It also looks at code coverage, which is a way to determine easily how effective the unit test suite is and to identify any areas in the software which could benefit from the creation of additional tests.
Dependency Injection and Inversion of Control (1 topic)
- Many developers have heard about the clear advantages of adhering to the SOLID principles of good design, but not all are fluent in applying them. Dependency injection is not only key to writing SOLID code, but it can also help implement late binding, improve extensibility, assist large teams practicing parallel development and improve maintainability. Importantly, it can also significantly improve the testability of code. This module not only looks at the different forms of dependency injection and at how to use dependency injection correctly, but also explains how to use an Inversion of Control (IoC) container to handle dependency management and complex construction automatically. Configuring the IoC container in code and in the application configuration file, which allows the application to be reconfigured without the need for recompilation, are both covered.
Doubles and Mocking (1 topic)
- When unit testing code, it is frequently necessary to test code that uses external resources, such as the file system, databases and remote services. To make this possible, a substitute for the Depended On Component (DOC) is injected into the System Under Test (SUT) that provides the necessary interface but which doesn't perform any external operations. These substitutes come in a number of forms, including fakes, stubs, spies and mocks. Although all of these forms can be written by hand, doing so is both tedious and time consuming. This module explains the different forms and shows how to use mocking frameworks to create and configure these substitutes with very little effort.
Proxy and Interceptor Patterns (1 topic)
- The Proxy pattern manages the invocation of an object, by hiding the true nature of the location and invocation mechanism of the object, and is typically used to make remote method calls. Proxies have a host of uses from the conventional RPC style to more elaborate uses such as virtual proxies, security proxies and caching proxies. Proxies can be built manually, using the CLR, or using third party libraries that can be used to automate the process. We will look at all three approaches to building effective proxies.
Appendix - AntiPatterns (1 topic)
- An anti-pattern (or antipattern) is a pattern that may be commonly used but that in practice is actually ineffective and/or counterproductive. This appendix describes developmental, architectural and managerial anti-patterns.
Appendix - Command Pattern with Undo (1 topic)
- The Command pattern module briefly describes how to implement commands that support undo. This appendix covers this additional capability in much greater detail.
Appendix – Façade and Adapter Patterns (1 topic)
- Just like an adapter in the real world, the Adapter pattern allows two related yet distinct systems to interoperate. This is particularly useful, for example, when a vendor defines an interface that is similar yet different to an interface that an existing application is already consuming. The Facade pattern provides a unifying interface to a set of interfaces in a subsystem, thereby providing a high-level interface that makes the subsystem easier to use. This appendix looks at both of these patterns and at how best to use them.
Appendix - Model View Controller (MVC) Pattern (1 topic)
- The Model-View-Controller (MVC) design pattern provides guidance on how to separate the various component parts of an application's user interface (UI). Building an application's UI without clear separation often leads to an inability to unit test the application, because tests are required to drive the user interface. This appendix will show how to separate the various concerns to build a unit testable Web UI application.
Appendix - Repository and Unit of Work Patterns (1 topic)
- An Object Relational Mapper (ORM) provides a good separation of business logic from persistence logic. However, writing code directly against a specific ORM often leads to code that is tightly coupled to the ORM in question. This has two effects: the first is that it makes it difficult to test the application's logic without a physical database, and the second is that it typically makes it very difficult to change to a different ORM. The Repository pattern creates an anti-corruption layer to allow you to take advantage of an ORM while still maintaining your ability to test and to change your choice of ORM simply and cleanly. This appendix looks at the Repository pattern and rounds off by looking at the Unit of Work pattern to aggregate many repositories and to provide centralised change tracking across all the repositories. This appendix uses Microsoft's Entity Framework (EF) as the ORM, evolving code from using EF directly to utilising the patterns to take full advantage of the ORM whilst keeping our code flexible and testable.
- Demonstrate proficiency in object-oriented programming techniques
- .NET experience