Está en la página 1de 25

GoF*

Patrones de diseño

*Gang of Four
GoF
 Catálogo de patrones de diseño.
 Década de los 90s, publicación del libro Design Patterns
escrito por el grupo Gang of Four (GoF) compuesto por
Erich Gamma, Richard Helm, Ralph Johnson y John
Vlisides, en el que se recogían 23 patrones de diseño
comunes.
 Creacionales, estructurales y de comportamiento.

2
Motivación 1

 El sistema necesita soportar diferentes tipos de


servicios externos, como calculadora de impuestos,
servicios de autorización de créditos, sistema de
inventarios, sistemas de descuentos, entre otros.
Cada sistema tiene un API diferente.

3
Adapter
 Problema:
 Cómo manejar interfaces incompatibles, o
proveer una interfaz estable a componentes
similares con diferentes interfaces?

 Comentemos…
 Cada servicio externo tiene una interfaz diferente.
 Cada sistema tiene un API que no podemos
modificar.
 Podemos tener diferentes implementaciones para
un tipo de servicio.
4
Adapter (2)
 Solución:
 Convertir la interface original de un componente
en otra interface, a través de un objeto adaptador
intermedio.

 Se adiciona un nivel de indirección con el objeto


que adapta la variación a interfaces externas.
 Incluir “adapter” en el nombre de la clase.

5
«interface» Adapters use interfaces and
ITaxCalculatorAdapter polymorphism to add a level of
indirection to varying APIs in other
getTaxes( Sale ) : List of TaxLineItems components.

TaxMasterAdapter GoodAsGoldTaxPro
Adapter

getTaxes( Sale ) : List of TaxLineItems


getTaxes( Sale ) : List of TaxLineItems

«interface» «interface»
IAccountingAdapter ICredit AuthorizationService
Adapter
postReceivable( Credit Payment )
postSale( Sale ) requestApproval(Credit Payment,TerminalI D, MerchantID)
... ...

«interface»
IInventoryAdapter
SAPAccountingAdapter GreatNorthernAccountingAdapter
...

postReceivable( Credit Payment ) postReceivable( Credit Payment )


postSale( Sale ) postSale( Sale )
... ...

6
Uso del adapter

:Register : SAPAccountingAdapter

makePayment
...
SOAP over
HTTP

postSale( sale )
xxx «actor»
: SAPSystem

the Adapter adapts to


interfaces in other components

7
Adapter – Especialización de
GRASP
Adapter soporta protected variatios respecto al cambio de interfaces externas o paquetes
externos, a través del uso de indirection con un objeto que aplica interfaces y
polimorfismo.

Protected Variation GRASP


Mechanism Principles

Low Coupling High Cohesion


Mechanism Mechanism

Polymorphism Indirection Pure


Example Mechanism Fabrication

GoF Design
Adapter Patterns

8
Factory
Llamado también Simple factory o Concrete factory.
Simplificación del GoF Abstract Factory
 Motivación
 Después de tener los Adaptadores, quién los crea? Cómo
determinar cual clase de adaptador crear? TaxMasterAdapter o
GoodAsGoldTaxProAdapter?
 Problema:
 Quién debería ser responsable de crear objetos

cuando existen consideraciones especiales, como una


lógica de creación compleja, un deseo de separar
responsabilidades de creación para mejorar la
cohesión, y demás?

9
Factory (2)
 Solución
 Crear un objeto de fabricación pura llamado Factory que maneje
la creación.

 Comentemos…
 Si asignamos esa responsabilidad a un objeto del dominio,
entonces está haciendo más que la lógica pura de la aplicación.
(está respondiendo a aspectos de conectividad con
componentes de software externos)
 Debemos diseñar siguiendo el principio de “separation of
concerns”
 Por lo tanto creamos un objeto que maneje esta creación y que
mantenga una alta cohesión.

10
Factory
ServicesFactory note that the factory methods
return objects typed to an
accountingAdapter : IAccountingAdapter interface rather than a class, so
inventoryAdapter : IInventoryAdapter that the factory can return any
taxCalculatorAdapter : ITaxCalculatorAdapter implementation of the interface

getAccountingAdapter() : IAccountingAdapter
getInventoryAdapter() : IInventoryAdapter
getTaxCalculatorAdapter() : ITaxCalculatorAdapter
...

if ( taxCalculatorAdapter == null )
{
// a reflective or data-driven approach to finding the right class: read it from an
// external property

String className = System.getProperty( "taxcalculator.class.name" );


taxCalculatorAdapter = (ITaxCalculatorAdapter) Class.forName( className ).newInstance();

}
return taxCalculatorAdapter;

11
Ventajas
 Separa la responsabilidad de creación
compleja en objetos de ayuda y cohesivos.
 Esconde (potencialmente) la lógica de la
creación compleja de objetos.
 Permite la introducción de estrategias de
administración de memoria que mejoran el
rendimiento.

 Patrones relacionados:
 Frecuentemente se usa con el patrón Singleton.
12
Singleton
 Motivación
 Del ejemplo anterior, entonces quién crea el ServiceFactory? O
cómo acceder a él?
 Comentemos…
 Solo una instancia del Factory es necesaria.
 Los métodos del Factory pueden ser llamados de varios
lugares en el código, tantos como donde se use un adaptador
a un servicio externo.
 Problema
 Exactamente una instancia de una clase es
permitida (singleton). Los objetos necesitan un
punto de acceso único y global.

13
Singleton
 Solución
 Defina un método estático de la clase que retorne el singleton.
UML notation: this '1' can optionally be used to
indicate that only one instance will be created (a
singleton)

1
ServicesFactory

UML notation: in a instance : ServicesFactory singleton static


class box, an attribute
underlined attribute or accountingAdapter : IAccountingAdapter
method indicates a inventoryAdapter : IInventoryAdapter
static (class level) taxCalculatorAdapter : ITaxCalculatorAdapter
member, rather than singleton
an instance member getInstance() : ServicesFactory static
method
getAccountingAdapter() : IAccountingAdapter
getInventoryAdapter() : IInventoryAdapter
getTaxCalculatorAdapter() : ITaxCalculatorAdapter
...

// static method
public static synchronized ServicesFactory getInstance()
{
if ( instance == null )
instance = new ServicesFactory()
return instance 14
}
Singleton
 El desarrollador obtiene una visibilidad global a una única instancia
a través del método estático getInstance
public class Register {
public void initialize() { … do some work …
// accessing the singleton Factory via the getInstance
call accountingAdapter =
ServicesFactory.getInstance().getAccountingAdapter();
… do some work …
} // other methods… } // end of class

1
:Register
:ServicesFactory

initialize
aa = getAccountingAdapter

the ‘1’ indicates that visibility


to this instance was achieved
...
via the Singleton pattern
15
Conclusión motivación 1…
 Al problema de Servicios Externos con
Interfaces variadas.
 Se combinaron los patrones adapter, factory y
singleton para proveer una variación protegida,
en las interfaces de servicios externos.
 El diseño final se basó en controller, creator,
protected variations, low coupling, high cohesion,
indirection, polimorphism, adapter, factory y
singleton.

16
1
:Store
:ServicesFactory

create
create :Register

accountingAdapter =
getAccountingAdapter
create : SAPAccounting
Adapter

accountingAdapter:
:Register
SAPAccountingAdapter

makePayment
create(cashTendered) : Payment SOAP over
HTTP

postSale( sale )
xxx «actor»
: SAPSystem

17
Conclusión (2)
 Ahora podemos decir:

“Para resolver el problema de Interfaces


variadas para servicios externos, use
adaptadores generados por un Singleton
Factory.”

18
Motivación 2
 Se tiene una lógica de precios compleja
 Descuentos por un día, por tipo de ciudadano.
 La estrategia de precios puede variar, ej durante
un periodo puede ser descuento de 10% de todas
las ventas, luego puede ser de $10 si la venta es
mayor de $200, etc.
Cada estrategia puede ser llamada regla,
política o algoritmo.
 Cómo diseñamos para variaciones en estos

algoritmos?

19
Strategy
 Problema
 Cómo diseñar para algoritmos o políticas variadas
pero relacionadas? Cómo diseñar con la habilidad
de cambiar estos algoritmos o políticas?

 Solución
 Definir cada algoritmo / política / estrategia en una
clase separada con una interfaz común.

20
Strategy - Solución
«interface»
ISalePricingStrategy

getTotal( Sale ) : Money

PercentDiscount AbsoluteDiscount ???


PricingStrategy OverThreshold PricingStrategy
PricingStrategy
percentage : float ...
discount : Money
getTotal( s:Sale ) : Money threshold : Money ...

getTotal( s:Sale ) : Money

{ {
return s.getPreDiscountTotal() * percentage pdt := s.getPreDiscountTotal()
} if ( pdt < threshold )
return pdt
else
return pdt - discount
}

21
Strategy – Solución (2)
 El objeto estrategia es ligado al objeto contexto (es decir
al objeto sobre el cual se aplica el algoritmo. Ej, sale)

lineItems[ i ] : :PercentDiscount
s : Sale
SalesLineItem PricingStrategy

t = getTotal
{ t = pdt * percentage }
loop st = getSubtotal

t = getTotal( s )

pdt = getPreDiscountTotal note that the Sale s is


passed to the Strategy so
that it has parameter
visibility to it for further
collaboration

22
 La referencia de Sale es
hacia la interfaz, no hacia la Sale needs attribute
clase concreta. visibility to its Strategy

Sale
«interface»
date 1 ISalePricingStrategy
...
pricingStrategy getTotal( Sale ) : Money
getTotal()
...

getTotal()
PercentDiscount AbsoluteDiscount
{
PricingStrategy OverThreshold
...
PricingStrategy
return pricingStrategy.getTotal( this ) percentage : float
discount : Money
} getTotal( Sale ) : Money threshold : Money

getTotal( Sale ) : Money

23
 Quién debería crear la estrategia? Una clase
Factory – singleton

1 El cambio de política es
PricingStrategyFactory
frecuente (incluso en
instance : PricingStrategyFactory horas), no es deseable
mantenerla en caché
getInstance() : PricingStrategyFactory sino leerla cada vez y
de una fuente externa.
getSalePricingStrategy() : ISalePricingStrategy
getSeniorPricingStrategy() : ISalePricingStrategy
...

{
String className = System.getProperty( "salepricingstrategy.class.name" );
strategy = (ISalePricingStrategy) Class.forName( className ).newInstance();
return strategy;
}

24
 Cuando se crea una venta, ella puede
inicializar su estrategia de precios.

1
:Register
:PricingStrategyFactory

makeNewSale
create :Sale

ps =
getSalePricingStrategy
create(percent) ps : PercentDiscount
PricingStrategy

25

También podría gustarte