View
13.882
Download
0
Tags:
Embed Size (px)
DESCRIPTION
In software engineering, a design pattern is a general reusable solution to a commonly occurring problem within a given context in software design Patterns are formalized best practices that the programmer must implement in the application.
Citation preview
Design Patterns Training
02/2014
Agenda
What’s a design pattern…
Pros / Cons
Families
Patterns x10
2All photos and pictures included in those slides are courtesy and copyright of their respective owners.
Homework
Object-Oriented Design : Coupling
Cohesion
Inheritance
Interface
Polymorphism
S.O.L.I.D. principles Refer A. Sauvinet mini-training
3
Definition
In software engineering, a design pattern is a general reusable solution to a commonly occurring problem within a given context in software design
Patterns are formalized best practices that the programmer must implement in the application
4
Pros / Cons
Pros : speed up development by providing tested, proven paradigms
Robust solution
Smart design
Flexibility
Re-usable
Cons : Usage reveals missing feature in programming language
Inappropriate use of patterns may unnecessarily increase complexity
Some patterns have impacts on performance
5
Families
3 main families : Creational patterns : control object creation mechanisms
Structural patterns : ease relationships between entities
Behavioral pattern : increase flexibility and communication between objects
2 extra families : Concurrency patterns
Lock
MDP : Messaging Design Pattern
Architectural patterns MVC : Model-View-Controller
MVVM : Model-View-ViewModel
MVP : Model-View-Presenter
Event-driven architecture
6
Families : Creational Patterns
Control object creation mechanisms Singleton*
Builder*
Abstract Factory
Prototype
Factory method*
Lazy initialization
Object pool
7
Families : Structural Patterns
Ease relationships between entities Adapter*
Decorator*
Composite*
Aggregate
Façade*
Proxy
8
Families : Behavioral Patterns
Increase flexibility and communication between objects Chain of responsibility*
Command
Iterator
Observer
Visitor*
Strategy*
9
And what about the famous IoC ?
Inversion of Control is not a pattern, it’s a programming technique.
Coupling is not known at compile time, only at runtime
Hands-on : Using a factory pattern
Using a service locator pattern
Using a dependency injection, for example:
• A constructor injection
• Parameter injection
• A setter injection
• An interface injection
Using a contextualized lookup
Using Template method design pattern
Using strategy design pattern
10
11
12
Singleton
Restricts instanciation of a class to one object.
Provides a global point of access to it
13Note : be careful with multithread, use (double) lock pattern
Singleton - Code
14
public static class Utils{
private static IUtilsInstance _instance;
public static IUtilsInstance Instance{
get{
if (_instance != null)_instance = new UtilsInstance();
}return _instance;
}}
}
Naive implementation
Singleton - Code
15
public static class Utils{
private static volatile object _lock = new object();
private static IUtilsInstance _instance;
public static IUtilsInstance Instance{
get{
if (_instance != null)return _instance;
lock (_lock){
if (_instance != null){
return _instance;}_instance = new UtilsInstance();return _instance;
}}set { _instance = value; }
}}
Builder
Separate construction of a complex object from its representation
Solution to the telescoping constructor anti-pattern Many parameters, mandatory or optional
17
Without Builder
public class BadCar
{
public bool HasGPS { get; private set; }
public bool IsCityCar { get; private set; }
public bool IsSportCar { get; private set; }
public bool IsCabrioletCar { get; private set; }
public int Seats { get; private set; }
public BadCar(bool hasGps);
public BadCar(bool hasGps, bool isCityCar);
public BadCar(bool isCabrioletCar, int seats);
public BadCar(bool hasGps, bool isCityCar, bool isSportCar, bool isCabrioletCar, int seats);
}
18
Program :
public void main()
{
var car = new BadCar(false, false, true, false, 2);
}
Without Builder
19
public class BadCabriolet : BadCar{
public BadCabriolet(bool hasGps) : base(hasGps) { }
public BadCabriolet(bool hasGps, bool isCityCar) : base(hasGps, isCityCar) { }
public BadCabriolet(bool isCabrioletCar, int seats) : base(isCabrioletCar, seats) { }
public BadCabriolet(bool hasGps, bool isCityCar, bool isSportCar, bool isCabrioletCar, int seats): base(hasGps, isCityCar, isSportCar, isCabrioletCar, seats)
{}
}
Issue with polymorphism :
With Builder
20
public class Car
{
public bool HasGPS { get; set; }
public bool IsCityCar { get; set; }
public bool IsSportCar { get; set; }
public bool IsCabrioletCar { get; set; }
public int Seats { get; set; }
}
public class CarBuilder{
private Car Car = new Car());
public Car GetCar(){
return Car;}
public CarBuilder SetSeats(int nbSeats){
Car.Seats = nbSeats;return this;
}
public CarBuilder SetSportsCar(){
Car.IsSportCar = true;return this;
}
public CarBuilder SetCabriolet();public CarBuilder SetGps();
…
}
• Wrap properties set into methods
• Really easy to make it « fluent »
public class Car
{
public bool HasGPS { get; private set; }
public bool IsCityCar { get; private set; }
public bool IsSportCar { get; private set; }
public bool IsCabrioletCar { get; private set; }
public int Seats { get; private set; }
public CarBuilder Builder { get; private set; }
private Car(CarBuilder Builder);
}
With Builder
21
public class Prog{
public void Main(){
var builder = new CarBuilder();
builder.SetSeats(2);builder.SetSportsCar();
var car = builder.GetCar();
...
var fluentCar = builder.SetSeats(2).SetSportsCar().SetGps().GetCar();}
}
• Initialization is wordy
• Extension is easy
• Polymorphism
Factory Method
Define an interface for creating a single object, but let subclasses decide which class to instantiate
Can be used to ease TDD mocking
3 different implementations Subclassing
Interface
Static
23
Note : Subclassing implementation depends on private constructor = class cannot be extended
if protected constructor = subclass have to redefine all factory methods !
Example
24
public interface ICar{
string GetType();}
public interface ICarFactory{
ICar MakeCar(int nbDoors);}
class Sedan : ICar{
public string GetType() { return "Sedan"; }}
class Coupe : ICar{
public string GetType() { return "Coupe"; }}
class CarFactory : ICarFactory{
public ICar MakeCar(int nbDoors){
return (nbDoors > 2) ? (ICar)new Sedan() : new Coupe();}
}
public class Proog
{public void Main(){
var f = new CarFactory();ICar coupe = f.MakeCar(2);ICar sedan = f.MakeCar(5);
}}
Adapter
Convert the interface of a class into another interface clients expect
Helps two incompatible interfaces to work together
26
Without adapter
27
public class DataParser{
private string Data;
public void SetData(string data){
this.Data = data;}
public void ParseData(){
Console.WriteLine(this.Data.Replace(" - ", " / "));}
}
public class DataProvider{
public string[] Datas;
public string GetStringData(){
return this.Datas.Aggregate(string.Empty, (current, data) => current + (data + " - "));}
}
public class Prog{
public void Main(){
var a = new DataParser();var b = new DataProvider();
a.SetData(b.GetStringData());a.ParseData();
}}
With adapter
28
public class DataParserFormat1Adapter{
public DataProvider B { get; set; }
public DataParserFormat1Adapter(DataProvider b){
this.B = b;}
public string GetStringData(){
return this.B.Datas.Aggregate(string.Empty, (current, data) => current + (data + " - "));}
}
public class Prog{
public void Main(){
var a = new DataParser();var b = new DataProvider();
var adapter = new DataParserFormat1Adapter(b);var data = adapter.GetStringData();
a.SetData(data);a.ComputeData();
}}
Decorator
Attach additional responsibilities to an object dynamically keeping the same interface
30
Without Decorator
31
public interface IArmor{
void Fight();
string GetDescription();}
public class SimpleArmor : IArmor{
public virtual void Fight(){
//Launch Simple missile}
public virtual string GetDescription(){
return "Armor Mark I";}
}
public class SimpleArmorWithLaser : SimpleArmor{
public override void Fight(){
base.Fight();LaunchLaser();
}
private void LaunchLaser(){
// Enable BBQ LAser}
public virtual string GetDescription(){
return "Mark II with Laser";}
}
Without Decorator
32
public class SimpleArmorWithTazer : SimpleArmor{
public override void Fight(){
base.Fight();this.EnableTazer();
}
private void EnableTazer(){
// Enable Heart Attack Tazer}
public override string GetDescription(){
return "Mark II with Tazer";}
}
Without Decorator
33
public class SimpleArmorWithTazer : SimpleArmor{
public override void Fight(){
base.Fight();this.EnableTazer();
}
private void EnableTazer(){
// Enable Heart Attack Tazer}
public override string GetDescription(){
return "Mark II with Tazer";}
}
public class SimpleWindowWithLaserAndTazer : SimpleArmorWithLaser{
public override void Fight(){
base.Fight();this.EnableTazer();
}
private void EnableTazer(){
// Enable Heart Attack Tazer}
public override string GetDescription(){
return base.GetDescription() + " and with Tazer";}
}
With Decorator
34
public abstract class ArmorDecorator : IArmor{
public IArmor DecoratedArmor { get; private set; }
public ArmorDecorator(IArmor decoratedArmor){
this.DecoratedArmor = decoratedArmor;}
public virtual void Fight(){
DecoratedArmor.Fight();}
public virtual string GetDescription(){
return DecoratedArmor.GetDescription();}
}
With Decorator
35
public class LaserDecorator : ArmorDecorator{
public LaserDecorator(IArmor decoratedArmor) : base(decoratedArmor) { }
public override void Fight(){
base.Fight();LaunchLaser();
}
private void LaunchLaser(){
// Enable BBQ Laser}
public override string GetDescription(){
return base.GetDescription() + " with Laser";}
}
With Decorator
36
public class LaserDecorator : ArmorDecorator{
public LaserDecorator(IArmor decoratedArmor) : base(decoratedArmor) { }
public override void Fight(){
base.Fight();LaunchLaser();
}
private void LaunchLaser(){
// Enable BBQ Laser}
public override string GetDescription(){
return base.GetDescription() + " with Laser";}
}
public class TazerDecorator : ArmorDecorator{
public TazerDecorator(IArmor decoratedArmor) : base(decoratedArmor) { }
public override void Fight(){
base.Fight();EnableTazer();
}
private void EnableTazer(){
// Enable Heazrt Attack Tazer}
public override string GetDescription(){
return base.GetDescription() + " with Tazer";}
}
With Decorator
37
public class Jarvis{
public void Main(){
IArmor ironman = new TazerDecorator(new LaserDecorator(new SimpleArmor()));
Console.WriteLine(ironman.GetDescription());}
}
Composite
Compose objects into tree structures to represent part-whole hierarchies
39
Composite Example
40
public interface IDrawable{
void Render();}
public class Ellipse : IDrawable{
public void Render(){
Console.WriteLine("Ellipse");}
}
public class Square: IDrawable{
public void Render(){
Console.WriteLine("Square");}
}
41
public class CompositeGraphic : IDrawable{
//Collection of Graphics.private readonly List<IDrawable> graphics;
public CompositeGraphic(){
//initialize generic Collection(Composition)graphics = new List<IDrawable>();
}
public void Add(IDrawable graphic);public void AddRange(params IDrawable[] graphic);public void Delete(IDrawable graphic);
//Render the graphic.public void Render(){
foreach (var childGraphic in graphics){
childGraphic.Render();}
}}
42
public class FrankensteinReturn{
public void Main(){
var eyes = new CompositeGraphic(new Square(), new Square());var mouth = new Ellipse();var head = new CompositeGraphic(new Square(), new Square(), new Square());
var frankenstein = new CompositeGraphic(head, eyes, mouth);}
}
43
Façade
Provide a unified interface to a set of interfaces in a subsystem
Facade defines a higher-level interface that makes the subsystem easier to use
BC example : Register in Global
44
Façade example
45
/* Complex parts */class CPU {
public void freeze() { ... }public void jump(long position) { ... }public void execute() { ... }
}
class Memory {public void load(long position, byte[] data) { ... }
}
class HardDrive {public byte[] read(long lba, int size) { ... }
}
Façade example
46
class ComputerFacade{
private CPU processor;private Memory ram;private HardDrive hd;
public ComputerFacade() {this.processor = new CPU();this.ram = new Memory();this.hd = new HardDrive();
}
public void Start() {processor.freeze();ram.load(BOOT_ADDRESS, hd.read(BOOT_SECTOR, SECTOR_SIZE));processor.jump(BOOT_ADDRESS);processor.execute();
}}
/* ServiceDesk */
class You {public static void main() {
var computer = new ComputerFacade();computer.Start();
}}
Chain of responsibility
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request.
Good practice : Loose coupling
BC example : login, register processes
48
Chain of responsibility example - pipeline
49
ProcessorTask
TaskTask
RequestLogin
ProcessorAuthentication
Task
Login = «testuser»
Password = « pwd123 »
Status = ok
User = null
Request
Login = «testuser»
Password = « pwd123 »
Status = ok
User = null
FraudTask
Request
Login
Password
Status = Forbidden by Fraud
User = null
Request
Infos
Status
50
Strategy
Define a family of algorithms, encapsulate each one, and make them interchangeable.
Strategy lets the algorithm vary independently from clients that use it.
O from SOLID : Open for extension but closed for modification.
51Note : For more information, key words : Policy-based design
Strategy example
52
interface DepositStrategy{
decimal Execute(decimal amount); };
class Eiole : DepositStrategy{
private decimal feeAmount = 10;
public decimal Execute(decimal amount) {
return amount + feeAmount;}
};
class Metacharge : DepositStrategy{
private decimal feeRate = 0,05;
public decimal Execute(decimal amount) {
return amount * (1 + feeRate);}
};
class DepositContext{
private List<DepositStrategy> strategies;...
private DepositStrategy PickStrategyFor(decimal amount) { // strategy with minimum fees; }
public decimal ExecuteStrategy(decimal amount) {
return this.strategy.Execute(amount);}
};
Strategy example
53
class DepositService{
public void Deposit(decimal amount) {
var context = new DepositContext();context.strategies.add(new Eiole());context.strategies.add(new Metacharge());
var totalAmount = context.ExecuteStrategy(amount);}
};
0 -> 200 € => Metacharge> 200 € => Eiole
Visitor
Represent an operation to be performed on the elements of an object structure.
Visitor lets you define a new operation without changing the classes of the elements on which it operates.
55Note : Implementation may have a real impact on performance !
Visitor example
56
interface IArticleVisitor{
void Visit(SportArticle sport);void Visit(PokerArticle poker);void Visit(TurfArticle turf);
}
interface IArticle{
string GetContent();...void Accept(IArticleVisitor visitor);
}
class SportArticle : IArticle{
public string GetContent()...
public void Accept(IArticleVisitor visitor) { visitor.Visit(this); }}
class SumUpArticleVisitor : IArticleVisitor{
private string Summary { get; set; }public string GetSummary() { return this.Summary; }
void Visit(SportArticle sport) { this.Summary += sport.GetContent().Substring(0, 200); }void Visit(PokerArticle poker) { this.Summary += poker.GetContent().Substring(0, 200); }void Visit(TurfArticle turf) { this.Summary += turf.GetContent().Substring(0, 200); }
public string BuildSummary(List<IArticle> articles) {
foreach(var article in articles) {article.Accept(this);
}return Summary;
}}
Visitor example
57
class SportArticle : IArticle{
public string MatchId { get; }
public void Accept(IArticleVisitor visitor) { visitor.Visit(this); }}
class UpdateStatusArticleVisitor : IArticleVisitor{
void Visit(SportArticle sport) { this.IsLive = Amelco.GetStatus(sport.MatchId) == 2; }
void Visit(PokerArticle poker) { }
void Visit(TurfArticle turf) { this.IsLive = PMC.GetStatus(turf.RaceId) == 99; }
public bool IsReferenceLive(IArticle article) {
article.Accept(this);return this.IsLive;
}}
class TurfArticle : IArticle{
public string RaceId { get; }
public void Accept(IArticleVisitor visitor) { visitor.Visit(this); }}
Conclusion
“With great power, comes great responsibilities” – Uncle Ben
• Design patterns are powerful tools, don’t hesitate to use them but beware of :
– Complexity
– Performance
58
59
About Betclic• Betclic Everest Group, one of the world leaders in online gaming, has a unique portfolio
comprising various complementary international brands: Betclic, Everest Gaming, bet-at-home.com, Expekt…
• Active in 100 countries with more than 12 million customers worldwide, the Group is committed to promoting secure and responsible gaming and is a member of several international professional associations including the EGBA (European Gaming and Betting Association) and the ESSA (European Sports Security Association).
• Through our brands, Betclic Everest Group places expertise, technological know-how and security at the heart of our strategy to deliver an on-line gaming offer attuned to the passion of our players.