.NET Best Practices: Architecture & Design Patterns

5 days
UARCH
5 days

Upcoming Sessions

Date:

Format:

Price:

Location:

Book now

Date:

Format:

Price:

Location:

Book now

Date:

Format:

Price:

Location:

Book now

Date:

Format:

Price:

Book now

Interested in a private company training? Request it here.

Improve your OO-design with S.O.L.I.D principles

The S.O.L.I.D principles were introduced by Robert C. Martin (also known as Uncle Bob) in 2000. The intention behind these principles is to make software designs more understandable, easier to maintain, and easier to extend. These principles are essential for every developer to know because they assist in writing better code and in better understanding code that was written with these principles in mind.

  • S - Single Responsibility
  • O - Open/Closed
  • L - Liskov Substitution
  • I - Interface Segregation
  • D - Dependency Inversion

Introduction to Patterns

One might not believe it, but design patterns did not originate in software architecture. Instead, patterns were first described in the 1970s by a real 'bricks and mortar' architect. A pattern is defined as a reusable solution to a common problem, without dictating the exact implementation. This characteristic makes patterns an ideal learning tool and a powerful means for communicating design ideas. Of course, there are also anti-patterns—approaches that are frequently used but are better avoided.

  • What is a Pattern?
  • The Gang of Four: Erich Gamma, Ralph Johnson, Richard Helm and John Vlissides.
  • Different kinds of design patterns: creational, structural and behavioral patterns.
  • Patterns everywhere: the difference between implementation, design and architecture patterns...
  • When to apply patterns, and when not to
  • Some anti-patterns, such as Loosy-Goosy

Singleton Pattern

We will start with a simple creational pattern, Singleton, and discuss its implementation in C#

  • What is a Singleton?
  • Singleton implementation choices in .NET
  • LAB: Building a Singleton in .NET

Code Reuse with Template Method

Many times you need to provide a base class for developers to inherit from. Here we discuss building a more robust version using the template method pattern.

  • Template Method - defer exact parts of an algorithm to inheriting classes, delegates, ...
  • LAB: Building a Template Method for a board game

Abstract Object Creation with Factories

When developing software, you often find yourself continuously creating new objects. While the fundamental act of creating new objects is not inherently problematic, it can lead to design challenges or increased complexity. Creational patterns such as Factory Method can assist you in managing object creation in a way that is appropriate for the situation.

  • Factory Method - delegating/hiding the creation of objects to a factory
  • Abstract Factory - abstracting to a factory to create families of objects
  • LAB: Implementing an Abstract Factory

The Strategy and Chain-Of-Responsibility Pattern

Strategy and Chain-Of-Responsibility are two behavioral patterns that assist in defining a family of algorithms, encapsulating each one, and making them interchangeable. By applying these patterns, you can allow the client to choose the algorithm that best suits their needs at runtime.

  • Strategy - template method without the annoying inheritance
  • LAB: Sorting Objects using Strategies
  • Chain of Responsibility - strategy to go through a chain of strategies
  • LAB: Using a Chain of Responsibility to implement a Builder

Collection Patterns

Iterators are a fundamental part of the .NET framework. They provide a generic way of navigating through collections. By using the yield keyword, you can create an iterator that returns a sequence of values. This approach is particularly useful when you need to asynchronously iterate over a collection.

  • Iterator - providing a generic way of navigating through collections, yield is your friend, asynchronously iterating a collection
  • Performance considerations on implementing IEnumerable

Improve Performance with the State and Flyweight Pattern

State and Flyweight are two structural patterns that help in managing object creation and state transitions. By applying these patterns, you can reduce memory consumption and improve the performance of your application.

  • State - defer state dependending logic to state classes, state machines,
  • Using the Stateless library
  • LAB: Implementing a VCR with the State patterns using the Stateless library
  • Flyweight - reduce memory consumption by preventing unnecessary creation of object

Object Hierarchy Patterns

Composite, Interpreter, Builder and Visitor are four patterns that help in managing complex object structures and operations. By applying these patterns, you can simplify the design of your application and improve its maintainability.

  • Composite - Building Part-Whole Hierarchies
  • Interpreter: Build your own expressive language-grammar and execute it.
  • How LINQ uses Interpreter - and how you can take advantage of it yourself.
  • Builder: Hide how complex hierarchies of objects get built - and allow variations.
  • XAML as the ultimate builder
  • Reflection: the .NET way for implementing your own builder
  • How NOT to use reflection
  • LAB: Building your own calculator with Interpreter and Builder
  • Visitor: When you need a lot of different operations on the same object structure
  • Building a pretty-printer using Visitor
  • Implementing Visitor the dynamic way
  • LAB: Implementing a Visitor to walk over a complex hierarchy of objects

The Observer and Mediator Pattern

How do you design classes that are ignorant of each other, and still can communicate effectively?.

  • Observer - notifying whoever is interested in what you have to say, events vs. delegates
  • Mediator - providing two-way communication between objects unaware of one another, correcly implementing INotifyPropertyChanged
  • LAB: Avoiding the String-based programming anti-pattern

Replace Inheritance with Adapter, Decorator and Proxy

Created objects do not tend to stand on their own. No, they start encapsulating other objects trying to create structure in, what otherwise would be a chaotic software environment. Structural patterns help at identifying and setting up relationships between objects.

  • Adapter - plugging in different objects into your code that do not fit
  • LAB: Building INotifyPropertyChanged as a generic Adapter
  • Decorator - altering the behavior of an object without the caller realising it
  • LAB: Changing IComparable<T> with a Decorator
  • Proxy - proxying requests made to the subject without changing the behavior

Hide Implementation Details with Facade

Facade is both a GOF pattern and a Microsoft pattern. Here we will discuss the diffences and similarities between the two.

  • Facade - hiding the complexity of subsystems from the caller

Automating your Code with Source Generators

Source Generators revolutionize the way we approach coding in C# by automating the creation of routine code directly within the C# compiler. This innovation not only circumvents the inefficiencies of reflection but also lays the groundwork for efficient Ahead-Of-Time (AOT) compilation, significantly optimizing performance.

  • What are Source Generators?
  • .NET 8 Source Generators
  • Implementing an incremental Source Generator
  • Source Generator Best Practices
  • LAB: Building your Own Source Generator

Build Flexible UIs with Model-View-Whatever

Most developers are not naturally skilled as graphic designers. This recognition has led to the development of design patterns that enable developers to concentrate on coding the application's behavior while allowing graphic designers to create compelling user interfaces. The cornerstone among these patterns is known as Model-View-Whatever (MVW), with Whatever being adaptable based on the specific technology in use. Grasping the MVW pattern is crucial, as it forms the foundation for developing both Windows and web applications.

  • Model-View-Controller: An ancient pattern back in fashion
  • The ASP.NET MVC Pattern
  • MVVM in Blazor - MVW taking advantage of powerful databinding capabilities
  • Command: Encapsulate behavior in objects
  • Implementing commands using closures
  • LAB: Using MVVM in a Blazor application

Reactive Programming

Have you ever encountered Reactive Programming? This significant advancement teaches you to harness Observables for programming. Through this approach, you'll learn to address common challenges that traditional Object-Oriented Programming finds difficult to solve. Additionally, we will delve into the Fluxor/Redux pattern, further expanding our toolkit for managing complex application states.

  • What are Observables?
  • Using Reactive Extensions
  • Applying the Redux pattern to simplify complex applications
  • LAB: Implementing a search system with Observables

Design Patterns Applied: Developing your own Reusable Library

When do you most need patterns? The answer is particularly when you're developing a framework on your own. Building a framework involves integrating new features while maintaining backward compatibility, a challenge that can be significantly simplified through the proper application of patterns. Therefore, in this final part of the training, we will construct a reusable library. During this process, we will encounter several challenges and address them by applying the appropriate patterns.

  • Adding the GoF Command pattern to MVVM
  • Using interfaces for flexibility
  • Building Command Objects - extending ICommand's interface
  • Adding Undo and Redo functionality to the command pattern
  • Using a CommandManager class
  • Challenge: retro-fitting our commands into MVVM without lots of changes
  • Implementing Undo-Redo using the Memento pattern
  • Choosing whether or not to add the Prototype pattern
  • Ideas on how to proceed with the command pattern
  • LAB: Implementing Undo/Redo logic as a reusable library

So, how can you become a better developer? One of the best ways is to learn about design patterns. Design Patterns provide reusable solutions for common software design challenges. In this training, we identify software design problems and explore how to address them using the most suitable Design Pattern. We will discuss creational, behavioral and structural patterns. All examples and labs use the latest LTS version of .NET and Visual Studio. Labs also work with any recent .NET and VS version.

This course is intended for experienced programmers who are familiar with C# and have a working experience of .NET.

Contact Us
  • Address:
    U2U nv/sa
    Z.1. Researchpark 110
    1731 Zellik (Brussels)
    BELGIUM
  • Phone: +32 2 466 00 16
  • Email: info@u2u.be
  • Monday - Friday: 9:00 - 17:00
    Saturday - Sunday: Closed
Say Hi
© 2025 U2U All rights reserved.