c# advanced l07-design patterns
DESCRIPTION
C# Advanced L07-Desgin PatternsTRANSCRIPT
Mohammad Shaker
mohammadshaker.com
@ZGTRShaker
2011, 2012, 2013, 2014
C# AdvancedL07–Design Patterns
Gang of Four (GoF) Gamma, Helm, Johnson, Vlissides
Gamma et al,
Design Patterns: Elements of Reusable Object-Oriented SoftwareAddison Wesley, 1995
Scope
• Patterns solve software structural problems like:– Abstraction,
– Encapsulation
– Information hiding
– Separation of concerns
– Coupling and cohesion
– Separation of interface and implementation
– Single point of reference
– Divide and conquer
• Patterns also solve non-functional
problems like:
– Changeability
– Interoperability
– Efficiency
– Reliability
– Testability
– Reusability
Types of Pattern
• There are 3 types of pattern:– Creational: address problems of creating an object in a flexible way. Separate creation, from
operation/use.
– Structural: address problems of using O-O constructs like inheritance to organize classes and objects
– Behavioral: address problems of assigning responsibilities to classes. Suggest both static relationships and patterns of communication
Classification of Design Patterns
Purpose
Creational Structural Behavioral
Factory Method Adapter Interpreter
Abstract Factory Bridge Template Method
Builder Composite Chain of Responsibility
Prototype Decorator Command
Singleton Façade Iterator
Flyweight Mediator
Proxy Memento
Observer
State
Strategy
Visitor
Patterns
Patterns
• Singleton
– Ensure a class only has one instance
– Provide a global point of access to it
• Abstract Factory
– Provide an interface for creating families of related or dependent objects without specifying
their concrete classes
• Factory Method
– Define an interface for creating an object but let subclasses decide which class to instantiate
– Lets a class defer instantiation to subclasses
• Prototype
– Specify the kinds of objects to create using a prototypical instance
– Create new objects by copying this prototype
Patterns
• Builder– Separate the construction of a complex object from its representation so that the same construction
process can create different representations
• Composite– Compose objects into tree structures to represent part-whole hierarchies
– Lets clients treat individual objects and compositions of objects uniformly
• Decorator– Attach additional responsibilities to an object dynamically
– Provide a flexible alternative to subclassing for extending functionality
• Adapter– Convert the interface of a class into another interface clients expect
– Lets classes work together that couldn’t otherwise because of incompatible interfaces
• Bridge– Decouple an abstraction from its implementation so that the two can vary independently
Patterns
• Façade– Provide a unified interface to a set of interfaces in a subsystem
– Defines an higher-level interface that makes the system easier to use
• Flyweight– Use sharing to support large numbers of fine-grained objects efficiently
• Proxy– Provide a surrogate or placeholder for another object to control access to it
• Iterator– Provide a way to access the elements of an aggregate object without exposing its
representation
• Command– Encapsulate a request as an object, thereby letting you parameterize clients with different
requests
Patterns
• Interpreter– Given a language, define a representation for its grammar along with an interpreter that uses the
representation to interpret sentences in the language
• Mediator– Define an object that encapsulate how a set of objects interact
– Promotes loose coupling by keeping objects from referring to each other explicitly
– Lets you vary their interaction independently
• Memento– Capture and externalize an object’s internal state
• Observer– Define a one-to-many dependency between objects so when one of them change state all its
dependents are updated automatically
• State– Allow an object to alter its behavior when its internal state changes
– The object will appear to change its class
Patterns
• Visitor
– Represent an operation to be performed on the elements of an object structure
– Lets you define a new operation without changing the classes of the elements on which
operates
• Strategy
– Define a family of algorithms
– Encapsulate each one
– Make them interchangeable
– Lets the algorithms vary independently from clients that use it
• Chain of responsibilities
– Avoid coupling the sender of a request to its receiver by giving more then one object a
chance to handle the request
– Chain the receiving objects and pass the request along the chain until an object handles it
Walk Through in Some Patterns
FactoryDefine an interface for creating an object but let subclasses decide which class to
instantiate. Lets a class defer instantiation to subclasses
Factoryclass ProductClass
{
public ProductClass() { … }
public ProductClass( int aInitValue ) { … }
};
class FactoryClass
{
public ProductClass GetNewInstance()
{ return new ProductClass(); }
public ProductClass GetNewInstance( int aInitValue )
{ return new ProductClass( aInitValue ); }
};
class Client
{
public void start()
{
// create a new factory
ProductFactory lFactory = new Factory();
// create objects
ProductClass lObj1 = lFactory.GetNewInstance();
ProductClass lObj2 = lFactory.GetNewInstance(4);
}
};
Factoryclass ProductClass
{
public ProductClass() { … }
public ProductClass( int aInitValue ) { … }
};
class FactoryClass
{
public ProductClass GetNewInstance()
{ return new ProductClass(); }
public ProductClass GetNewInstance( int aInitValue )
{ return new ProductClass( aInitValue ); }
};
class Client
{
public void start()
{
// create a new factory
ProductFactory lFactory = new Factory();
// create objects
ProductClass lObj1 = lFactory.GetNewInstance();
ProductClass lObj2 = lFactory.GetNewInstance(4);
}
};
StrategyDefines a family of algorithms, encapsulates each algorithm, and
makes the algorithms interchangeable within that family.
Strategypublic interface IBehaviour { public int moveCommand();}
public class AgressiveBehaviour implements IBehaviour{
public int moveCommand(){ \\AgressiveBehaviour Behaviour }
}
public class DefensiveBehaviour implements IBehaviour{
public int moveCommand(){ \\DefensiveBehaviour Behaviour }
}
public class NormalBehaviour implements IBehaviour{
public int moveCommand(){ \\NormalBehaviour Behaviour }
}
public class Robot {
IBehaviour behaviour;
String name;
public Robot(String name)
{ this.name = name; }
public void setBehaviour(IBehaviour behaviour)
{ this.behaviour = behaviour; }
public void move()
{ behaviourزmoveCommand(); }
}
Strategypublic interface IBehaviour { public int moveCommand();}
public class AgressiveBehaviour implements IBehaviour{
public int moveCommand(){ \\AgressiveBehaviour Behaviour }
}
public class DefensiveBehaviour implements IBehaviour{
public int moveCommand(){ \\DefensiveBehaviour Behaviour }
}
public class NormalBehaviour implements IBehaviour{
public int moveCommand(){ \\NormalBehaviour Behaviour }
}
public class Robot {
IBehaviour behaviour;
String name;
public Robot(String name)
{ this.name = name; }
public void setBehaviour(IBehaviour behaviour)
{ this.behaviour = behaviour; }
public void move()
{ behaviourزmoveCommand(); }
}
Three different Strategies for Robot movement
Strategypublic interface IBehaviour { public int moveCommand();}
public class AgressiveBehaviour implements IBehaviour{
public int moveCommand(){ \\AgressiveBehaviour Behaviour }
}
public class DefensiveBehaviour implements IBehaviour{
public int moveCommand(){ \\DefensiveBehaviour Behaviour }
}
public class NormalBehaviour implements IBehaviour{
public int moveCommand(){ \\NormalBehaviour Behaviour }
}
public class Robot {
IBehaviour behaviour;
String name;
public Robot(String name)
{ this.name = name; }
public void setBehaviour(IBehaviour behaviour)
{ this.behaviour = behaviour; }
public void move()
{ behaviourزmoveCommand(); }
}
Assigning a robot behaviour
Strategypublic interface IBehaviour { public int moveCommand();}
public class AgressiveBehaviour implements IBehaviour{
public int moveCommand(){ \\AgressiveBehaviour Behaviour }
}
public class DefensiveBehaviour implements IBehaviour{
public int moveCommand(){ \\DefensiveBehaviour Behaviour }
}
public class NormalBehaviour implements IBehaviour{
public int moveCommand(){ \\NormalBehaviour Behaviour }
}
public class Robot {
IBehaviour behaviour;
String name;
public Robot(String name)
{ this.name = name; }
public void setBehaviour(IBehaviour behaviour)
{ this.behaviour = behaviour; }
public void move()
{ behaviourزmoveCommand(); }
}
public static void main(String[] args) {
Robot r1 = new Robot("Big Robot");
Robot r2 = new Robot("George v.2.1");
Robot r3 = new Robot("R2");
r1.setBehaviour(new AgressiveBehaviour());
r2.setBehaviour(new DefensiveBehaviour());
r3.setBehaviour(new NormalBehaviour());
r1.move();
r2.move();
r3.move();
r1.setBehaviour(new DefensiveBehaviour());
r2.setBehaviour(new AgressiveBehaviour());
r1.move();
r2.move();
r3.move();
}
Strategypublic interface IBehaviour { public int moveCommand();}
public class AgressiveBehaviour implements IBehaviour{
public int moveCommand(){ \\AgressiveBehaviour Behaviour }
}
public class DefensiveBehaviour implements IBehaviour{
public int moveCommand(){ \\DefensiveBehaviour Behaviour }
}
public class NormalBehaviour implements IBehaviour{
public int moveCommand(){ \\NormalBehaviour Behaviour }
}
public class Robot {
IBehaviour behaviour;
String name;
public Robot(String name)
{ this.name = name; }
public void setBehaviour(IBehaviour behaviour)
{ this.behaviour = behaviour; }
public void move()
{ behaviourزmoveCommand(); }
}
public static void main(String[] args) {
Robot r1 = new Robot("Big Robot");
Robot r2 = new Robot("George v.2.1");
Robot r3 = new Robot("R2");
r1.setBehaviour(new AgressiveBehaviour());
r2.setBehaviour(new DefensiveBehaviour());
r3.setBehaviour(new NormalBehaviour());
r1.move();
r2.move();
r3.move();
r1.setBehaviour(new DefensiveBehaviour());
r2.setBehaviour(new AgressiveBehaviour());
r1.move();
r2.move();
r3.move();
}
Simply change the Strategy and the
behavior will change
SingletonWhen one, and only one, instance of class is needed. Providing
a global point of access to it.
Singletonprivate readonly SqlConnection _sqlConnection;
const CONNECTION_STRING = (@"Data Source=127.0.0.1;database=soa;User id=sa1;Password=sa1;“;
public static SqlConnection GetSqlConnectionSingleton()
{
if (_sqlConnection == null)
{
_sqlConnection = new SqlConnection(CONNECTION_STRING );
}
return _sqlConnection;
}
Any client will call GetSqlConnectionSingleton (public) and has no direct access to _sqlConnection (private)
Singleton for an Object
public sealed class Singleton
{
private static Singleton _instance;
private Singleton() { }
public static Singleton GetSingleton()
{
if (_instance == null) _instance = new Singleton();
return _instance;
}
}
No one can instantiate this (since the constructor is private), like this:Singleton s = new Singleton();
Singleton for an Object
public sealed class Singleton
{
private static Singleton _instance;
private Singleton() { }
public static Singleton GetSingleton()
{
if (_instance == null) _instance = new Singleton();
return _instance;
}
}
One Instance and One Instance Only will be Created for this Class Object
Database Connection Singleton private readonly SqlConnection _sqlConnection;
const CONNECTION_STRING = (@"Data Source=127.0.0.1;database=soa;User id=sa1;Password=sa1;“;
public static SqlConnection GetSqlConnectionSingleton()
{
if (_sqlConnection == null)
{
_sqlConnection = new SqlConnection(CONNECTION_STRING );
}
return _sqlConnection;
}
Database Connection Singleton private readonly SqlConnection _sqlConnection;
const CONNECTION_STRING = (@"Data Source=127.0.0.1;database=soa;User id=sa1;Password=sa1;“;
public static SqlConnection GetSqlConnectionSingleton()
{
if (_sqlConnection == null)
{
_sqlConnection = new SqlConnection(CONNECTION_STRING );
}
return _sqlConnection;
}
Singleton for an Object in Multi-threaded Application?
Any Need to Adjust?
Singleton for an Object in Multi-threaded Applicationpublic sealed class Singleton
{
private static Singleton _instance;
private static object _lockThis = new object();
private Singleton() { }
public static Singleton GetSingleton()
{
lock (_lockThis)
{
if (_instance == null) _instance = new Singleton();
}
return _instance;
}
}
MultitonIs an extension of the singleton pattern. When one, and only one, instance of
class is needed that corresponds to a key. Providing a global point of access to it.
MultitonDictionary <Key, SingletonObject> _singletonInstances;public static SingletonInstances GetMultiton(string key){
lock (_lock){
if (!_singletonInstances.ContainsKey(key)) _singletonInstances.Add(key, new Multiton());}return _instances[key];
}
MultitonDictionary <Key, SingletonObject> _singletonInstances;public static SingletonInstances GetMultiton(string key){
lock (_lock){
if (!_singletonInstances.ContainsKey(key)) _singletonInstances.Add(key, new Multiton());}return _instances[key];
}
Software Architectural Patterns
MVCModel View Controller
MVVMModel View View Model