Design Patterns
Telerik Academy Alpha
HQC
Table of contents
What is Design Pattern?
What is Design Pattern?
- General, repeatable and reusable solution to a common problem in software design
What is not Design Pattern?
- Not f inished design that can be transformed directly into code
- Not code snippets
- Not algorithms
- Not components/libraries
- Not language-specific
When to use a Desing Pattern?
- Solutions to problems that occur more times
- Solutions that require several steps
- Not all problems need all steps
- Patterns can be overkill if a solution is a simple linear set of instructions!
- Do not use a pattern only because you can
- Overdesign is evil!
Drawbacks
- Patterns do not lead to a direct code reuse
- Patterns are deceptively simple
- Teams may suffer from pattern overload
- Integrating patterns into the software development process is a human-intensive activity
- Use patterns if you understand them well
Creational Design Patterns
What?
-
Deal with object creation mechanisms
-
Trying to create objects in a manner suitable to the situation
-
Composed of two dominant ideas
-
Encapsulating knowledge about which concrete classes the system uses
-
Hiding how instances of these concrete classes are created and combined
-
Singleton
Singleton
Ensures single instance of an object for the project
What is Singleton Design Pattern?
-
Class that is guaranteed to have only a single instance and provides global point of access to it
-
Examples: window manager, file system, console, application logger, state object
-
-
Encapsulated "just-in-time initialization" or "initialization on first use".
When to use Singleton?
-
Different parts of a system need to access a single object
-
System requires global access to the object instance
-
Expensive instantiation -> lazy loading
How to implement Singleton?
public Logger
{
private static Logger instance;
// private constructor ensures that
// Logger cannot be instantiated from outside
private Logger()
{ }
// provide access to the single instance
public static Logger Instance
{
get
{
// instantiate on the first access
if(instance == null)
instance = new Logger();
return instance;
}
}
public void Log(string log)
{
Console.WriteLine(log);
}
}
Problems
-
The Singleton design pattern is one of the most inappropriately used patterns
-
Designers frequently use Singletons in a misguided attempt to replace global variables
-
Singletons can make testing harder because they often rely on static methods and properties
-
Abstract Factory
Abstract Factory
Defines abstract interface for creating a family of related types of objects
What is Abstract Factory?
-
Defines an abstract interface for creating a family of related types of objects
-
The created objects are returned as interface types or base types
-
Multiple factories can implement the abstract interface
When to use Abstract Factory?
-
If an application is to be portable, it needs to encapsulate platform dependencies
-
Too often, this encapsulation is not engineered in advance, and lots of #ifdef case statements with options for all currently supported platforms begin to procreate like rabbits throughout the code
How to implement Abstract Factory?
interface IContinentFactory { // AbstractFactory
Herbivore CreateHerbivore();
Carnivore CreateCarnivore();
}
class AfricaFactory : IContinentFactory {
public Herbivore CreateHerbivore() {
return new Wildbeаst();
}
public Carnivore CreateCarnivore() {
return new Lion(); // Constructor can be internal
}
}
class AmericaFactory : IContinentFactory {
public Herbivore CreateHerbivore() {
return new Bison();
}
public Carnivore CreateCarnivore() {
return new Wolf();
}
}
Problems
-
This pattern can introduce a lot of accidental complexity
-
One of the main drawbacks is the extra complexity and writing the code during the initial stages
-
-
Does your application really need an Abstract Factory?
Quizlet
- The console is/ is not an example of Singleton?
- Must Singleton objects be initialized with the start of the programme?
- Does Singleton facilitate testing?
- Abstract factory facilitates controlling the behavior of the objects?
- Must the client specify the way each object from the factory is created?
- Nice implementation of Abstract factory?
public abstract class AbstractFactory {
abstract Color GetColor(String color);
abstract Shape GetShape(String shape) ;
}
public class ShapeFactory: AbstractFactory {
private override Shape GetShape(String shapeType){
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
}
return null;
}
private override Color GetColor(String color) {
return null;
}
}
Structural Design Patterns
What is Structural Design Pattern?
-
Describe ways to assemble objects to implement a new functionality
-
Simple way to realize relationships between entities
-
All about Class and Object composition
-
Structural class-creation patterns use inheritance to compose interfaces
-
Structural object-patterns define ways to compose objects to obtain new functionality
-
Composite
Composite
Treat in the same way individual objects or groups of objects
When to use Composite?
-
We have different objects and we want to treat them the same way
-
We want to present hierarchy of objects
-
Tree-like structures
-
-
Examples in .NET Framework
-
Windows.Forms.Control and its derived classes
-
System.Web.UI.Control and its derived classes
-
System.Xml.XmlNode and its derived classes
-
How to implement Component?
abstract class MailReceiver
{
public abstract void SendMail();
}
class EmailAddress : MailReceiver
{
public override void SendMail() { /*...*/ }
}
class GroupOfEmailAddresses : MailReceiver
{
private List<MailReceiver> participants;
public override void SendMail()
{
foreach(var p in participants)
{
p.SendMail();
}
}
}
static void Main()
{
var rootGroup = new GroupOfEmailAddresses();
rootGroup.SendMail();
}
Decorator
Decorator
Add functionality to existing objects at run-time
What is Decorator Design Pattern?
- Extends the original component
-
Alternative to inheritance (class explosion)
-
Support Open-Closed principle
-
Flexible design, original object is unaware
-
When to use Decorator?
When to use Decorator?
-
You want to add behavior or state to individual objects at run-time
-
Inheritance is not feasible because it is static and applies to an entire class
-
This flexibility can be achieved with the following design
How to implement Decorator?
abstract class Decorator : LibraryItem {
protected LibraryItem libraryItem;
public Decorator(LibraryItem libraryItem) {
this.libraryItem = libraryItem;
}
public override void Display() {
libraryItem.Display();
}
}
class Borrowable : Decorator {
protected List<string> borrowers = new List<string>();
public Borrowable(LibraryItem libraryItem) : base(libraryItem) {}
public void BorrowItem(string name) {
borrowers.Add(name);
libraryItem.NumCopies--;
}
public override void Display() {
base.Display();
foreach (string borrower in borrowers) {
Console.WriteLine(" borrower: " + borrower);
}
}
}
Decorator vs Inheritance
- Decorating can provide new behavior at runtime for individual objects, and the change affects all instances of the original class; Subclassing adds behavior at compile time
-
Example: TextView class.
- You want a scrolled text view - ScrolledTextView class.
- You want a border around text view - BorderedTextView.
- You want both border and scroll - ScrolledBorderedTextView
Result - duplication of the effort + class explosion
-
Decorator pattern is used to decorate the existing classes without changing the old behavior.
- You can test your decorator in isolation of the decorated object (not possible with inheritance to mock the parent class)
Adapter
Adapter
Converts the given class'es interface into another class requested by the client
What is Adapter Design Pattern?
-
Converts the given class' interface into another class requested by the client
-
Wraps an existing class with a new interface
-
Impedance match an old component to a new system
-
-
Allows classes to work together when this is impossible due to incompatible interfaces
When to use Adapter?
-
An "off the shelf" component offers compelling functionality that you would like to reuse
-
But its "view of the world" is not compatible with the philosophy and architecture of the system currently being developed
How to implement Adapter?
interface ITarget {
List<string> GetProducts();
}
public class VendorAdaptee
{
public List<string> GetListOfProducts() {
List<string> products = new List<string>();
products.Add("Gaming Consoles");
products.Add("Television");
products.Add("Books");
products.Add("Musical Instruments");
return products;
}
}
class VendorAdapter:ITarget {
public List<string> GetProducts() {
VendorAdaptee adaptee = new VendorAdaptee();
return adaptee.GetListOfProducts();
}
}
class ShoppingPortalClient {
static void Main(string[] args) {
ITarget adapter = new VendorAdapter();
foreach (string product in adapter.GetProducts()) {
Console.WriteLine(product);
}
Console.ReadLine();
}
}
Quizlet
-
Composite pattern handles a single object and group of objects differently?
-
Decorator pattern works in favour of keeping the Open-Closed principle?
-
If you have an old class with API that does not work anymore which pattern are you going to use?
-
Differences between Decorator pattern and inheritance?
-
Adapter pattern creates new implementations of the objects of old system?
-
The 'Adaptee' class is the one which interface is not compatible or the class that takes care of the implementing the new interface?
-
The 'Target' class is?
8. Which design pattern is illustrated with:
Behavioral Design Patterns
What is Behavioral Design Pattern?
-
Concerned with communication (interaction) between the objects
-
Either with the assignment of responsibilities between objects
-
Or encapsulating behavior in an object and delegating requests to it
-
-
Increase flexibility in carrying out cross-classes communication
Template Method
Template Method
The program skeleton of an algorithm in an operation, deferring some steps to subclasses
What is Template method Design Pattern?
-
Defines the base of an algorithm in a method, leaving some implementation to its subclasses
-
Allows the subclasses to redefine the implementation of some of the parts of the algorithm
-
Doesn’t let the subclasses to change the algorithm structure
-
-
Relies on inheritance
-
Strategy on composition
-
-
Usually, override of virtual or abstract method (hook)
When to use Template Method?
-
Two or more classes should follow the same common algorithm or workflow
-
The workflow never changes
-
Subclasses may redefine the steps (not order)
-
Some steps may be implemented in the base class (DRY)
How to implement Template Method?
public abstract class HotDrink {
public void PrepareRecipe()
{
BoilWater(); Brew(); PourInCup(); AddSpices();
}
protected abstract void Brew();
protected abstract void AddSpices();
private void BoilWater() { ... }
private void PourInCup() { ... }
}
public class Coffee : HotDrink {
protected override void Brew() { ... }
protected override void AddSpices() { ... }
}
public class Tea : HotDrink {
protected override void Brew() { ... }
protected override void AddSpices() { ... }
}
Questions
[C# HQC] Design Patterns
By telerikacademy
[C# HQC] Design Patterns
- 1,162