Design pattern
Design Patterns is a modern classic in the literature of object-oriented development, offering timeless and elegant solutions to common problems in software design. It describes patterns for managing object creation, composing objects into larger structures, and coordinating control flow between objects. The book provides numerous examples where using composition rather than inheritance can improve the reusability and flexibility of code. Note, though, that it’s not a tutorial but a catalog that you can use to find an object-oriented design pattern that’s appropriate for the needs of your particular application–a selection for virtuoso programmers who appreciate (or require) consistent, well-engineered object-oriented designs. Design Patterns is a modern classic in the literature of object-oriented development, offering timeless and elegant solutions to common problems in software design. It describes patterns for managing object creation, composing objects into larger structures, and coordinating control flow between objects. The book provides numerous examples where using composition rather than inheritance can improve the reusability and flexibility of code. Note, though, that it’s not a tutorial but a catalog that you can use to find an object-oriented design pattern that’s appropriate for the needs of your particular application–a selection for virtuoso programmers who appreciate (or require) consistent, well-engineered object-oriented designs.
So now let’s dive what’s under the hood of the design pattern in this article I try to explain and give some sample diagramm and snipset code example .
Book reference
Design Patterns: Elements of Reusable Object-Oriented Software
Pattern Facade
Provide a unified interface to a set of interfaces in a subsystem. Façade defines a higher-level interface that makes the subsystem easier to use.
Frequency of use: high
* Objectif de ce design Pattern :
a pour but de regrouper les interfaces d’un ensemble d’objets en une interface unifiée rendant cet ensemble simple à utiliser . En gros cela veut dire que nous exposons à nos client une interface permettant d’accéder à un ensemble de service sous jacent
Exemple :
Nous pouvons imaginer un système client Server, dans lequel le serveur expose un ensemble de service via une interface (la facade) que le client s’attacchera d’attaquer via RMI (remote method invocation) / corba …
Cette manière de faire permet de facilité le développement d’applications distribuées en masquant au client la complexité situé coté serveur (traitement lourds , EJb transactionnel … )
UML class diagram

=> Code source
package facade; import java.util.List; public class ClientWebservice { public static void main(String[] args) { WebServiceAuto webserviceAuto = new WebServiceAutoImpl(); System.out.println(webserviceAuto.document(0)); System.out.println(webserviceAuto.document(1)); List<String> resultats = webserviceAuto.chercheVehicules(6000, 1000); if(resultats.size() >0 ){ System.out.println("véhicule est comprix entre 5000 et 7000"); for (String resultat : resultats) { System.out.println(" "+resultat); } } } } package facade; import java.util.List; public interface WebServiceAuto { String document(int index); List<String> chercheVehicules(int prixMoyen ,int ecartMax); } package facade; import java.util.List; public class WebServiceAutoImpl implements WebServiceAuto{ Catalogue catalogue = new ComposantCatalogue(); GestionDocument gestionDocument = new ComposantGestionDocument(); public String document(int index) { return gestionDocument.document(index); } public List<String> chercheVehicules(int prixMoyen, int ecartMax) { return catalogue.retrouveVehicules(prixMoyen, ecartMax); } } package facade; public interface GestionDocument { String document (int index ) ; } package facade; public class ComposantGestionDocument implements GestionDocument { public String document(int index) { return "Document numéro "+index ; } } package facade; import java.util.List; public interface Catalogue { List<String> retrouveVehicules(int prixMin,int prixMax); } package facade; import java.util.ArrayList; import java.util.List; public class ComposantCatalogue implements Catalogue { Object [] descriptionVehicule ={ "Berline 5 portes ", 6000, "Compact 3 portes " , 4000, "Espace 5 portes",8000, "Break 5 portes ",7000, "Coupé 2 portes ",9000,"Utilitaire 3 portes ",5000 }; /** * Partie métier sattachant a retourver les listes de vehicules entre 2 ecarts de prix */ public List<String> retrouveVehicules(int prixMin, int prixMax) { int index , taille ; List<String> resultat = new ArrayList<String>(); taille = descriptionVehicule.length/2; for (int i = 0; i < taille; i++) { int prix = ((Integer)descriptionVehicule[2*i+1]).intValue(); if((prix >= prixMin ) && (prix <= prixMax)){ resultat.add((String) descriptionVehicule[2*i]); } } return resultat; } }
Pattern Observer
package observer; public class Program { public static void main(String[] args) { FluxRss flux1= new FluxRss(); flux1.setDescription("Android latest news "); flux1.setModele("Android"); IObservateur ob = new FluxObservateur(flux1); ob.informe(); } } package observer; import java.util.ArrayList; import java.util.List; public abstract class Sujet { List<IObservateur> obs = new ArrayList<>(); void ajoute (IObservateur o){ obs.add(o); } void retire(IObservateur o ){ obs.remove(o); } public void notifie (){ for (IObservateur element : obs) { element.update(); } } } package observer; public class FluxRss extends Sujet { public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getModele() { return modele; } public void setModele(String modele) { this.modele = modele; } String description; String modele; } public interface IObservateur { String update (); void informe(); } public class FluxObservateur implements IObservateur{ private FluxRss fluxRss; String texte = ""; public FluxObservateur(FluxRss fluxRss) { this.fluxRss = fluxRss; fluxRss.ajoute(this); } @Override public String update() { texte = "Description Feed: "+fluxRss.getDescription()+" \nName: "+fluxRss.getModele(); return texte ; } public void informe(){ System.out.println(update()); } }
Abstract Factory
Ce pattern permet de regrouper la création des objets en familles sans que l’on est à savoir comment les classes concrètes sont crées .
Dans cet exemple de diagramme de classe la classe dites cliente catalogue recurpère l’objet dit « fabriquer » ( AutomobileEssence , automobileElectrique )
Souvent on utilise aussi le pattern Builder plus simple à implémenter
public class Catalogue { public static int nbAutos = 3 ; public static void main(String[] args) { Scanner reader = new Scanner(System.in); FabriqueVehicule fabrique = null ; Automobile[] autos = new Automobile[nbAutos]; System.out.println("Vehicule essence (1) ou essence (2)"); String choix = reader.next(); if(choix.equals("1")){ fabrique = new FabriqueVehiculeEssence(); } if(choix.equals("2")){ fabrique = new FabriqueVehiculeElectrique(); } for (int i=0;i<nbAutos;i++) { autos[i] = fabrique.creeAutomobile("standard", "pink",2, 2.666); } for (Automobile automobile : autos) { automobile.afficheCaracteristique(); } } package abstractfactory; public interface FabriqueVehicule { Automobile creeAutomobile(String modele,String couleur,int puissance,double espace); } package abstractfactory; public class FabriqueVehiculeElectrique implements FabriqueVehicule{ public Automobile creeAutomobile(String modele, String couleur, int puissance, double espace) { return new AutomobileElectrique(modele, couleur, puissance, espace); } } package abstractfactory; public class FabriqueVehiculeEssence implements FabriqueVehicule{ public Automobile creeAutomobile(String modele, String couleur, int puissance, double espace) { return new AutomobileEssence(modele, couleur, puissance, espace); } } package abstractfactory; public abstract class Automobile { String modele ; String couleur ; int puissance ; double espace ; public Automobile(String modele,String couleur,int puissance, double espace ){ this.modele=modele; this.couleur=couleur; this.puissance= puissance ; this.espace=espace ; } public abstract void afficheCaracteristique(); } public class AutomobileElectrique extends Automobile{ public AutomobileElectrique(String modele, String couleur, int puissance, double espace) { super(modele, couleur, puissance, espace); } public void afficheCaracteristique() { System.out.println("Automobile electrique \n"+ "couleur "+couleur+" puissance: "+puissance+" espace :"+espace ); } } public class AutomobileEssence extends Automobile{ public AutomobileEssence(String modele, String couleur, int puissance, double espace) { super(modele, couleur, puissance, espace); } public void afficheCaracteristique() { System.out.println("Automobile electrique \n"+ "couleur "+couleur+" puissance: "+puissance+" espace :"+espace ); } }
Pattern Builder
definition
![]() |
Separate the construction of a complex object from its representation so that the same construction process can create different representations.
Frequency of use: |
public class BuilderExample { public static void main(String[] args) { Cook cook = new Cook(); //director PizzaBuilder hawaiianPizzaBuilder = new HawaiianPizzaBuilder();//concretebuilder PizzaBuilder spicyPizzaBuilder = new SpicyPizzaBuilder(); cook.setPizzaBuilder(hawaiianPizzaBuilder); cook.constructPizza(); Pizza hawaiian = cook.getPizza(); cook.setPizzaBuilder(spicyPizzaBuilder); cook.constructPizza(); Pizza spicy = cook.getPizza(); } } public class Cook { /** * @uml.property name="pizzaBuilder" * @uml.associationEnd */ private PizzaBuilder pizzaBuilder; /** * @param pb * @uml.property name="pizzaBuilder" */ public void setPizzaBuilder(PizzaBuilder pb) { pizzaBuilder = pb; } public Pizza getPizza() { return pizzaBuilder.getPizza(); } public void constructPizza() { pizzaBuilder.createNewPizzaProduct(); pizzaBuilder.buildDough(); pizzaBuilder.buildSauce(); pizzaBuilder.buildTopping(); } } abstract class PizzaBuilder { /** * @uml.property name="pizza" * @uml.associationEnd */ protected Pizza pizza; /** * @return * @uml.property name="pizza" */ public Pizza getPizza() { return pizza; } public void createNewPizzaProduct() { pizza = new Pizza(); } public abstract void buildDough(); public abstract void buildSauce(); public abstract void buildTopping(); } public class HawaiianPizzaBuilder extends PizzaBuilder { public void buildDough() { pizza.setDough("cross"); } public void buildSauce() { pizza.setSauce("mild"); } public void buildTopping() { pizza.setTopping("ham+pineapple"); } } class SpicyPizzaBuilder extends PizzaBuilder { public void buildDough() { pizza.setDough("pan baked"); } public void buildSauce() { pizza.setSauce("hot"); } public void buildTopping() { pizza.setTopping("pepperoni+salami"); } } public class Pizza { /** * @uml.property name="dough" */ private String dough = ""; /** * @uml.property name="sauce" */ private String sauce = ""; /** * @uml.property name="topping" */ private String topping = ""; /** * @return * @uml.property name="dough" */ public String getDough() { return dough; } /** * @param dough * @uml.property name="dough" */ public void setDough(String dough) { this.dough = dough; } /** * @return * @uml.property name="sauce" */ public String getSauce() { return sauce; } /** * @param sauce * @uml.property name="sauce" */ public void setSauce(String sauce) { this.sauce = sauce; } /** * @return * @uml.property name="topping" */ public String getTopping() { return topping; } /** * @param topping * @uml.property name="topping" */ public void setTopping(String topping) { this.topping = topping; } }
Protype Pattern
package prototype; public abstract class Cookie implements Cloneable{ public Cookie clone() throws CloneNotSupportedException{ Cookie copy = (Cookie)super.clone(); return copy; } abstract void prototypeFactory(int x) ; abstract void printValue() ; } package prototype; /** * @author artaud */ public class CookieMachineClient { /** * @uml.property name="cookie" * @uml.associationEnd */ private Cookie cookie; // could have been a private Cloneable cookie; public CookieMachineClient(Cookie cookie){ this.cookie = cookie; } public Cookie makeCookie() throws CloneNotSupportedException{ return cookie.clone(); } public static void main(String[] args) { try { Cookie cookie= null; CoconutCookie mycookie= new CoconutCookie(100); CookieMachineClient vCookieMachineClient = new CookieMachineClient(mycookie); for(int i =0;i<10;i++){ cookie = vCookieMachineClient.makeCookie(); //clone our objectg cookie.prototypeFactory(i*100);//verify that our clone object is really there cookie.printValue(); } } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } package prototype; /** * * @author artaud * */ public class CoconutCookie extends Cookie{ int x ; public CoconutCookie(int x ) { this.x=x; } @Override void printValue() { System.out.println("Value : "+x); } @Override void prototypeFactory(int x) { this.x=x ; } }
Decorator Pattern
Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
Frequency of use: medium

package decorator; public class LauchCoffeeOrder { public static void main(String[] args) { Coffee coffee = new SimpleCoffee(); System.out.println("Cost : "+ coffee.getCost()+" Ingredients : "+ coffee.getIngredients()); coffee = new ColdCofee(coffee); System.out.println("Cost : "+ coffee.getCost()+" Ingredients : "+ coffee.getIngredients()); coffee = new LatteCoffee(coffee); System.out.println("Cost : "+ coffee.getCost()+" Ingredients : "+ coffee.getIngredients()); } } package decorator; public interface Coffee { public int REGULAR_PRICE = 10; public int getCost(); public String getIngredients(); } package decorator; public class SimpleCoffee implements Coffee{ @Override public int getCost() { return REGULAR_PRICE; } @Override public String getIngredients() { return "Coffee "; } } package decorator; public abstract class CoffeeDecorator implements Coffee{ /** * @uml.property name="coffee" * @uml.associationEnd */ private Coffee coffee; public final String SEPARATOR = ", "; public CoffeeDecorator(Coffee coffee) { this.coffee = coffee ; } public int getCost() { return coffee.getCost(); } public String getIngredients() { return coffee.getIngredients(); } } package decorator; public class ColdCofee extends CoffeeDecorator{ public ColdCofee(Coffee coffee) { super(coffee); } public int getCost(){ return super.getCost() + 5; } public String getIngredients(){ return super.getIngredients()+ SEPARATOR + " Ice "; } } package decorator; public class LatteCoffee extends CoffeeDecorator{ public LatteCoffee(Coffee coffee) { super(coffee); } public int getCost(){ return super.getCost() + 10; } public String getIngredients(){ return super.getIngredients()+ SEPARATOR + " Milk "; } } visitor Pattern
Composite Pattern
Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
Frequency of use: medium high
UML class diagram

package composite; public class LaunchComputation { public static void main(String[] args) { PointComponent curve = new Point(1, 2050,10 ); PointComponent curve2 = new Point(1, 2010,10 ); PointComponent curve3 = new Point(1, 3010,10 ); ScenarioComponent scenarioHighRisk = new ScenarioHighVolatility(); scenarioHighRisk.add(curve); scenarioHighRisk.add(curve2); scenarioHighRisk.add(curve3); scenarioHighRisk.operation(); PointComponent curve4 = new Point(1, 210,10 ); PointComponent curve5 = new Point(1, 2010,10 ); PointComponent curve6 = new Point(1, 3010,10 ); ScenarioComponent scenarioLowRisk = new ScenarioLowVolatility(); scenarioLowRisk.add(curve4); scenarioLowRisk.add(curve5); scenarioLowRisk.add(curve6); scenarioLowRisk.operation(); } } package composite; public interface PointComponent { public void operation(); public float getDay(); public float getPrice(); public void setPrice(float price); public int getSensibility(); } package composite; public class Point implements PointComponent{ float day; // abcisse float price;//ordonnée int sensibility; //sensibility pricing variation Point (float day,float price,int sensibility){ this.day=day; this.price = price ; this.sensibility = sensibility; } /** * @return the day */ public float getDay() { return day; } /** * @param day the day to set */ public void setDay(float day) { this.day = day; } /** * @return the price */ public float getPrice() { return price; } /** * @param price the price to set */ public void setPrice(float price) { this.price = price; } /** * @return the sensibility */ public int getSensibility() { return sensibility; } /** * @param sensibility the sensibility to set */ public void setSensibility(int sensibility) { this.sensibility = sensibility; } @Override public void operation() { } } package composite; import java.util.ArrayList; import java.util.List; public abstract class ScenarioComponent implements PointComponent{ private PointComponent curveScenario ; List<PointComponent> points = new ArrayList<PointComponent>(); ScenarioComponent(){} public List<PointComponent>add(PointComponent point){ points.add(point); return points; } public List<PointComponent>remove(PointComponent point){ points.remove(point); return points; } public List<PointComponent> getChilds(){ return this.points; } public void operation(){ curveScenario.operation(); } public float getDay(){ return curveScenario.getDay(); } public float getPrice(){ return curveScenario.getPrice(); } public void setPrice(float price){ curveScenario.setPrice(price); } public int getSensibility(){ return curveScenario.getSensibility(); } /** * @uml.property name="pointComponent" * @uml.associationEnd inverse="scenarioComponent:composite.PointComponent" */ private PointComponent pointComponent; /** * Getter of the property <tt>pointComponent</tt> * @return Returns the pointComponent. * @uml.property name="pointComponent" */ public PointComponent getPointComponent() { return pointComponent; } /** * Setter of the property <tt>pointComponent</tt> * @param pointComponent The pointComponent to set. * @uml.property name="pointComponent" */ public void setPointComponent(PointComponent pointComponent) { this.pointComponent = pointComponent; } } package composite; public class ScenarioHighVolatility extends ScenarioComponent{ public ScenarioHighVolatility(){}; public void operation(){ System.out.println("\n**** High Volatility scenario *****"); for (PointComponent point : points) { float scenarioPrice = point.getPrice() - point.getSensibility()-20; point.setPrice(scenarioPrice); System.out.println("Price : " + point.getPrice()); } } } package composite; public class ScenarioLowVolatility extends ScenarioComponent{ public ScenarioLowVolatility(){}; public void operation(){ System.out.println("**** Low Volatility scenario *****"); for (PointComponent point : points) { float scenarioPrice = point.getPrice() - point.getSensibility()- 5; point.setPrice(scenarioPrice); System.out.println("Price : " + point.getPrice()); } } }
Observator Pattern
- Le pattern observer permet d’avoir des objets faiblement couplés.
- Ce pattern est basé sur une relation : de un à plusieurs.
- Au lieu de coupler nos objets directement, on préfère coupler les interfaces qu’ils implémentent.
- Grâce à ce pattern, nos objets restent indépendants les uns des autres !
Très utiliser dans les systèmes de facturation(ajout client, traitement auxiliaire) ou dans les interfaces UI comme le Swing
Where is the controller in this example?? The controllers are the
instances of the anonymous classes which handle the button
presses.
package observer; import java.awt.Button; import java.awt.Frame; import java.awt.Panel; import java.awt.TextField; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; public class CounterGui extends Frame { // The counter. (The model!) private int counter = 0; // The view. private TextField tf = new TextField(10); public CounterGui(String title) { super(title); Panel tfPanel = new Panel(); tf.setText("0"); tfPanel.add(tf); add("North", tfPanel); Panel buttonPanel = new Panel(); Button incButton = new Button("Increment"); incButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { counter++; tf.setText(counter + ""); } } ); buttonPanel.add(incButton); Button decButton = new Button("Decrement"); decButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { counter--; tf.setText(counter + ""); } } ); buttonPanel.add(decButton); Button exitButton = new Button("Exit"); exitButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); } } ); buttonPanel.add(exitButton); add("South", buttonPanel); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } } ); } public static void main(String[] argv) { CounterGui cg = new CounterGui("CounterGui"); cg.setSize(300, 100); cg.setVisible(true); } }
Visitor
The benefit of this pattern is that if the logic of operation changes, then we need to make change only in the visitor implementation rather than doing it in all the item classes.
Another benefit is that adding a new item to the system is easy, it will require change only in visitor interface and implementation and existing item classes will not be affected.
The drawback of visitor pattern is that we should know the return type of visit() methods at the time of designing otherwise we will have to change the interface and all of its implementations. Another drawback is that if there are too many implementations of visitor interface, it makes it hard to extend.
An advance way to use this pattern is to couple it with Chain responsability http://www.tutorialspoint.com/design_pattern/chain_of_responsibility_pattern.htm
package visitor.model; import visitor.IMessageInVisitor; import visitor.ItemElement; public class MessageIn implements ItemElement{ String id; double price ; double positions; public MessageIn(String id , double price , double positions) { this.id= id; this.price = price; this.positions = positions ; } public String getId() { return id; } public void setId(String id) { this.id = id; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public double getPositions() { return positions; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("MessageIn [id="); builder.append(id); builder.append(", price="); builder.append(price); builder.append(", positions="); builder.append(positions); builder.append("]"); return builder.toString(); } public void setPositions(double positions) { this.positions = positions; } @Override public TradeXmlOutput accept(IMessageInVisitor visitor) { return visitor.visit(this); } } package visitor.model; public class TradeXmlOutput { public String reference ; public String getReference() { return reference; } public void setReference(String reference) { this.reference = reference; } public double getPrice() { return price; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("TradeXmlOutput [reference="); builder.append(reference); builder.append(", price="); builder.append(price); builder.append("]"); return builder.toString(); } public void setPrice(double price) { this.price = price; } public double price ; } package visitor; import java.util.ArrayList; import visitor.model.MessageIn; public class Client { public static void main(String[] args) { MessageIn message = new MessageIn("TPX15784", new Double("200"), new Double(100)); IMessageInVisitor visitor = new MessageInVisitorImpl(); ArrayList<MessageIn> messages = new ArrayList<MessageIn>(); messages.add(message); for (ItemElement e : messages) { System.out.println(e.accept(visitor).toString()); } } } package visitor; import visitor.model.MessageIn; import visitor.model.TradeXmlOutput; public interface IMessageInVisitor { public TradeXmlOutput visit(MessageIn message); } package visitor; import visitor.model.TradeXmlOutput; public interface ItemElement { public TradeXmlOutput accept(IMessageInVisitor visitor); } package visitor; import visitor.model.MessageIn; import visitor.model.TradeXmlOutput; public class MessageInVisitorImpl implements IMessageInVisitor{ @Override public TradeXmlOutput visit(MessageIn message) { TradeXmlOutput e = new TradeXmlOutput(); //Map our element e.reference = message.getId(); e.price = message.getPrice()*2; return e; } } seconde version decoupling treatment .package visitor; import java.util.ArrayList; import visitor.model.MessageIn; public class Client { public static void main(String[] args) { //Mock data In MessageIn message = new MessageIn("TPX15784", new Double("200"), new Double(100)); IMessageInVisitor visitor = new MessageInReferenceVisitorImpl(); ArrayList<MessageIn> messages = new ArrayList<MessageIn>(); messages.add(message); for (ItemElement e : messages) { visitor.setOutput(e.accept(visitor)); visitor = new MessageInPriceVisitorImpl() ; visitor.setOutput(e.accept(visitor)); } //print RESULT System.out.println(visitor.getOutput().toString()); } } package visitor; import visitor.model.MessageIn; import visitor.model.TradeXmlOutput; public class MessageInPriceVisitorImpl extends IMessageInVisitor{ @Override public TradeXmlOutput visit(MessageIn message) { TradeXmlOutput e = getOutput(); e.price = message.getPrice()*2; return e; } } package visitor; import visitor.model.MessageIn; import visitor.model.TradeXmlOutput; public class MessageInReferenceVisitorImpl extends IMessageInVisitor{ @Override public TradeXmlOutput visit(MessageIn message) { //Map our element TradeXmlOutput e = getOutput(); e.reference = message.getId(); return e; } } package visitor; import visitor.model.MessageIn; import visitor.model.TradeXmlOutput; public abstract class IMessageInVisitor { TradeXmlOutput output; public abstract TradeXmlOutput visit(MessageIn message); public TradeXmlOutput getOutput() { if (output ==null){ return new TradeXmlOutput(); } return output; } public void setOutput(TradeXmlOutput output) { this.output = output; } }
Singleton Pattern
- Permet de n’avoir q’une instance du POJO java .
public class Singleton { private static Singleton instance = null; private Singleton() {} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
annexe
http://userpages.umbc.edu/~tarr/dp/lectures/Observer.pdf
http://www.dofactory.com/Patterns/Patterns.aspx
http://www.javaworld.com/javaworld/javatips/jw-javatip29.html
http://www.croes.org/gerald/blog/observateurs-observables-vs-publish-subscribe/51/
Exemple in .NET
http://www.dofactory.com/Patterns/Patterns.aspx
Livre
Gamma, Helm, Johnson, Vlissides, »Design Patterns, » Addison-Wesley, 1994, ISBN 0-201-63361-2