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.
2. Agenda
What’s a design pattern…
Pros / Cons
Families
Patterns x10
All photos and pictures included in those slides are courtesy and copyright of their respective owners.
2
4. 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
5. 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
6. 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
9. Families : Behavioral Patterns
Increase flexibility and communication between objects
Chain of responsibility*
Command
Iterator
Observer
Visitor*
Strategy*
9
10. 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
13. Singleton
Restricts instanciation of a class to one object.
Provides a global point of access to it
Note : be careful with multithread, use (double) lock pattern
13
14. Singleton - Code
Naive implementation
public static class Utils
{
private static IUtilsInstance _instance;
public static IUtilsInstance Instance
{
get
{
if (_instance != null)
_instance = new UtilsInstance();
}
return _instance;
}
}
}
14
15. Singleton - Code
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; }
}
}
15
16.
17. Builder
Separate construction of a complex object from its representation
Solution to the telescoping constructor anti-pattern
Many parameters, mandatory or optional
17
18. 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
public
public
public
BadCar(bool
BadCar(bool
BadCar(bool
BadCar(bool
hasGps);
hasGps, bool isCityCar);
isCabrioletCar, int seats);
hasGps, bool isCityCar, bool isSportCar, bool isCabrioletCar, int seats);
}
Program :
public void main()
{
var car = new BadCar(false, false, true, false, 2);
}
18
19. Without Builder
Issue with polymorphism :
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)
{
}
}
19
20. With Builder
public class
{
public
public
public
public
public
}
Car
bool HasGPS { get; set; }
bool IsCityCar { get; set; }
bool IsSportCar { get; set; }
bool IsCabrioletCar { get; set; }
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 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 SetSportsCar()
{
Car.IsSportCar = true;
return this;
}
public CarBuilder Builder { get; private set; }
private Car(CarBuilder Builder);
}
public CarBuilder SetCabriolet();
public CarBuilder SetGps();
…
}
• Wrap properties set into methods
• Really easy to make it « fluent »
20
21. With Builder
public class Prog
{
public void Main()
{
var builder = new CarBuilder();
• Initialization is wordy
• Extension is easy
• Polymorphism
builder.SetSeats(2);
builder.SetSportsCar();
var car = builder.GetCar();
...
var fluentCar = builder.SetSeats(2).SetSportsCar().SetGps().GetCar();
}
}
21
22.
23. 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
Note : Subclassing implementation depends on private constructor = class cannot be extended
if protected constructor = subclass have to redefine all factory methods !
23
24. Example
public interface ICar
{
string GetType();
}
class Sedan : ICar
{
public string GetType() { return "Sedan"; }
}
public interface ICarFactory
{
ICar MakeCar(int nbDoors);
}
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);
}
}
24
25.
26. Adapter
Convert the interface of a class into another interface clients expect
Helps two incompatible interfaces to work together
26
27. Without adapter
public class DataParser
{
private string Data;
public void SetData(string data)
{
this.Data = data;
}
public void ParseData()
{
Console.WriteLine(this.Data.Replace(" - ", " / "));
}
public class Prog
{
public void Main()
{
var a = new DataParser();
var b = new DataProvider();
a.SetData(b.GetStringData());
a.ParseData();
}
}
}
public class DataProvider
{
public string[] Datas;
public string GetStringData()
{
return this.Datas.Aggregate(string.Empty, (current, data) => current + (data + " - "));
}
}
27
28. With adapter
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();
}
}
28
31. Without Decorator
public interface IArmor
{
void Fight();
string GetDescription();
}
public class SimpleArmor : IArmor
{
public virtual void Fight()
{
//Launch Simple missile
}
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";
}
}
public virtual string GetDescription()
{
return "Armor Mark I";
}
}
31
32. Without Decorator
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";
}
}
32
33. Without Decorator
public class SimpleArmorWithTazer : SimpleArmor
{
public override void Fight()
{ public class SimpleWindowWithLaserAndTazer : SimpleArmorWithLaser
base.Fight();
{
this.EnableTazer();
public override void Fight()
}
{
base.Fight();
private void EnableTazer()
this.EnableTazer();
{
}
// Enable Heart Attack Tazer
}
private void EnableTazer()
}
{
public override string GetDescription()
// Enable Heart Attack Tazer
{
}
return "Mark II with Tazer";
}
public override string GetDescription()
{
return base.GetDescription() + " and with Tazer";
}
}
33
34. With Decorator
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();
}
}
34
35. With Decorator
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";
}
}
35
36. With Decorator
public class LaserDecorator : ArmorDecorator
{
public LaserDecorator(IArmor decoratedArmor) : base(decoratedArmor) { }
public override void Fight()
{
base.Fight();
public class TazerDecorator : ArmorDecorator
{ LaunchLaser();
}
public TazerDecorator(IArmor decoratedArmor) : base(decoratedArmor) { }
}
private void override void Fight()
public LaunchLaser()
{
{
// Enable BBQ Laser
base.Fight();
}
EnableTazer();
}
public override string GetDescription()
{
private void EnableTazer()
return base.GetDescription() + " with Laser";
{
}
// Enable Heazrt Attack Tazer
}
public override string GetDescription()
{
return base.GetDescription() + " with Tazer";
}
}
36
37. With Decorator
public class Jarvis
{
public void Main()
{
IArmor ironman = new TazerDecorator(new LaserDecorator(new SimpleArmor()));
Console.WriteLine(ironman.GetDescription());
}
}
37
40. Composite Example
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");
}
}
40
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();
}
}
}
41
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);
}
}
42
44. 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
45. Façade example
/* 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) { ... }
}
45
46. Façade example
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();
}
}
46
47.
48. 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
49. Chain of responsibility example - pipeline
Task
Task
Task
Processor
Login
Processor
Request
Login = «testuser»
Password = « pwd123 »
Status = ok
User = null
Authentication
Task
Request
Login = «testuser»
Password = « pwd123 »
Status = ok
User = null
Request
Infos
Status
Fraud
Task
Request
Login
Password
Status = Forbidden by Fraud
User = null
49
51. 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.
Note : For more information, key words : Policy-based design
51
53. Strategy example
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
53
54.
55. 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.
Note : Implementation may have a real impact on performance !
55
57. Visitor example
class SportArticle : IArticle
{
public string MatchId { get; }
public void Accept(IArticleVisitor visitor) { visitor.Visit(this); }
}
class TurfArticle : IArticle
{
public string RaceId { 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;
}
}
57
58. 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
61. 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-athome.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.