Está en la página 1de 20

Patrones de Diseño

Ingeniría de Software II - Universidad Distrital

Oscar Armando Ortiz Soto - 20042020071.

9 de junio de 2009

Índice

1. Patrones Creacionales 2
1.1. Factory-Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2. Singleton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3. Abstract Factory . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.4. Prototype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.5. Builder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2. Patrones Para Manejo De Colecciones 4


2.1. Composite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.2. Iterator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.3. Flyweight . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.4. Visitador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

3. Patrones Estructurales 7
3.1. Decorador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3.2. Cadena de Responsabilidades . . . . . . . . . . . . . . . . . . . . 8
3.3. Adaptador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.4. Fachada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.5. Proxy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.6. Bridge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.7. Aggregate Enforcer . . . . . . . . . . . . . . . . . . . . . . . . . . 12

4. Patrones Comportamentales 13
4.1. Comando . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
4.2. Mediador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
4.3. Memento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
4.4. Observer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
4.5. Interpreter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.6. State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.7. Strategy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
4.8. Template Method . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

1
5. Patrones Concurrentes 18
5.1. Critical Section . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
5.2. Consistent Lock Order . . . . . . . . . . . . . . . . . . . . . . . . 19
5.3. Guarded Suspension . . . . . . . . . . . . . . . . . . . . . . . . . 19
5.4. Read-Write Lock . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

1. Patrones Creacionales

1.1. Factory-Method

Algunos clientes suelen saber que sublclase de una jerarquía puede utilizar,
pero no sabe exactamente cual, es por esto que se dene una superclase que
dene métodos generales para que sus subclases los sobreescriban, de tal forma
que un cliente pueda mantener una referencia de la superclase. Por ejemplo se
tiene una aplicación de registro, que permite enviar mensaje que ya sea por
consola o a un archivo plano, en general debe existir un método que permita
registrar un mensaje, y una subclase por cada tipo de registro que se quiera, en
este patrón un cliente debe denir cual clase debe utilizar, lo que puede resultar
en un problema. Para evitar esto, se dene una clase fabrica que debe decidir
que objeto es el que necesita el cliente y crearlo.

1.2. Singleton

Algunas veces es necesario asegurar que un objeto sea creado únicamente


una vez durante la ejecución de una aplicación. Por ejemplo la conexión a una
base de datos se debería crear una vez. Por ejemplo, una aplicación que hace
un registro de mensajes en archivos planos, como el visto en el patrón 1.1, en
el caso de la clase encargada de hacer el registro en un archivo, se debería crear
un solo objeto de este tipo, para esto se dene un atributo del tipo de la misma
clase, además es estático y privado, el constructor de la clase es privado para
evitar su creación, y se dene un método de inicialización del objeto, el cual
verica si el objeto estático es nulo, si es así lo crea y lo retorna, si no es nulo
simplemente lo retorna.

1.3. Abstract Factory

Abstract Factory pertenece al grupo de los patrones creacionales, su objetivo


es seleccionar un objeto fabrica de una jerarquía de clases, de la misma forma
que sucede en el patrón de diseño factory method, es decir que este es utilizado
en este caso, a partir de la fabrica obtenida, se crea un objeto según un criterio
general.
Un ejemplo de este patrón es el siguiente; se tiene una jerarquía de clases
que consiste en una clase padre denominada Carro y de la cual pueden heredan
CarroLujoso y CarroNoLujoso, por otra parte se tiene una Clase denominada
Camioneta de la cual heredan CamionetaLujosa y CamionetaNoLujosa, a partir
de este par de jerarquías se pueden crear dos fabricas de carros, la primera es

2
FabricaCarrosLujosos y la segunda los CarrosNoLujosos, las cuales heredan de
una clase denominada Fabrica, esta clase permite obtener una fabrica de acuerdo
a un criterio ya establecido, por ejemplo el tipo de carro, en este punto se hace
uso del patrón Factory Method. Finalmente cada fabrica permitirá crear un
carro de acuerdo a un criterio de tipo, es decir si es una camioneta o un carro,
obteniendo así el objeto nal.

Ventajas:

Se agrupan los objetos de diferentes familias de acuerdo a un criterio caracterís-


tico para permitir su creación. Se crean clases únicas que seleccionan los objetos
a crear por las clases cliente.

Desventajas:

Es difícil incorporar nuevos objetos.

1.4. Prototype

Este patrón de diseño tiene como nalidad la creación de objetos a partir


de uno ya creado, es decir que lo duplica o lo clona, es útil cuando se tiene un
objeto en el cual su creación puede llegar a ser compleja, o depende de alguna
conguración en particular.
Hace uso de la interfaz Clonable en el lenguaje de programación Java, la
cual se implementa en el objeto que pretende ser clonado, por características
de este lenguaje, este patrón presenta dos desviaciones, la primera se presenta
en objetos que son clonados supercialmente y la segunda en objetos clonados
a fondo, en el primer caso solo se clonan los objetos primitivos, a partir de la
llamada al método clone() de la clase padre, los objetos de la clase clonada serán
los mismos que para la clase original. En el segundo caso, la copia a fondo, se
crea una copia de los objetos que hacen parte del original.

Ventajas:

Permite obtener copia de un objeto en ejecución. Permite decidir si las copias


creadas son a fondo o superciales

1.5. Builder

Builder hace parte del grupo de los patrones de diseño encargados de la


creación de objetos, existen casos de creación de objetos en el cual su lógica es
compleja, en los cuales los pasos que se llevan a cabo pueden ser implementados
de diferentes maneras, creando objetos con diferente representación. Este pa-
trón de diseño pretende dar mayor eciencia al proceso de creación de objetos.
Sugiere mover la lógica de creación de un objeto a una clase aparte, esta clase
es denominada builder, Puede existir mas de una representación de esta clase,
cada una de las cuales tiene un desarrollo diferente para la creación del objeto.

3
El patrón builder es útil cuando es necesario cuando el algoritmo de creación
de un objeto debe ser independiente de las partes que lo conforman, también es
útil cuando se necesita crear mas de una representación de un objeto.
Cada uno de los pasos que se llevan a cabo para la creación del objeto son
denidos como métodos, en una interfaz a ser implementada por los diferentes
constructores (builders) concretos. Existirá entonces una clase que sabe cuales
son los pasos a seguir para crear el objeto, la cual es denominada director,
es responsable de invocar los diferentes métodos de la clase builder para la
creación del objeto nal. Así los objetos clientes no necesitan comunicarse con
los diferentes métodos de construcción del objeto.

Ventajas:

Se separa la lógica de creación de objetos complejos, la cual llega a ser indepen-


diente de sus partes. Se pueden crear diferentes representaciones de un mismos
objeto. El cliente recibe su objeto concreto sin conocer cuales son los pasos
necesarios para su creación.

2. Patrones Para Manejo De Colecciones

2.1. Composite

Este patrón de diseño esta enfocado en el manejo de colecciones, existen ob-


jetos individuales y objetos compuesto los cuales pueden contener otros objetos
de su misma clase, el patrón Composite es útil en el diseño de interfaces comunes
para estos dos tipos de objetos, de tal forma que los clientes ven a estos objetos
uniformemente. Es decir que lo dos pueden ser tratados de la misma manera.
Una forma sencilla de ver este patrón es por medio de un árbol, en el cual
hay nodos terminales(componentes compuestos) y no terminales (componentes
individuales). De esta forma se logra una composición recursiva.
Generalmente la interfaz dene métodos que permiten incluir nuevos objetos
del mismo tipo (addComponent), y métodos que permiten obtener un objeto
determinado (getComponent)

Ventajas:

Es útil cuando se requiere representar una jerarquía todo-parte. Los clientes


ignoran la diferencia entre los objetos individuales y los objetos compuestos. Es
fácil incluir nuevas clases de componentes.

2.2. Iterator

Este patrón de diseño permite a los cliente manipular las colecciones de


objetos de una manera secuencial, de tal forma que no tenga que conocer como
están representados sus contenidos, es decir como se almacenan internamente.
Esto debido a que en java existen múltiples formas de representar colecciones
de objetos. Para lograr esto se sugiere que la clase contenedora de la colección

4
provea una interfaz pública comúnmente denominada Iterador, a los diferentes
objetos que acceden a su contenido. Esta interfaz debe proveer métodos a los
objetos cliente para navegar a través de la lista de objetos.
El iterador puede funcionar también como un ltro, es decir que se puede
iterar sobre una colección sobre el siguiente objeto pero que cumpla una condi-
ción especica, en estos casos la clase que implementa la interaz Iterador dbe
retornar un conjunto de objetos seleccionados que cumplan con la condición del
ltro.
Este patrón de diseño tiene dos enfoques el primero es un Iterador interno,
por ejemplo, se tiene una clase Candidate, otra AllCandidates que tiene una
colección de objetos de la clase Candidate y además implementa la interfaz
Iteratod del paquete java.util, sobre-escribiendo los métodos next() y hasNext(),
es decir que la clase AllCandidates debe saber en que momento puede ir a un
siguiente elemento (hasNext) y devolver el elemento (next) posteriormente. Para
lograrlo debe tener un atributo que permita conocer el estado de la lista, en este
caso se obtiene un objeto de la clase Enumeration desde el Vector que contiene
los objetos de la clase Candidate, el objeto de la clase Enumeration permite
obtener el siguiente elemento, así se puede saber si hay un siguiente elemento
y se guarda en una variable globar para retornarlo en la llamada a next(). Con
esto se concluye que la clase AllCandidates la cual tiene la colección sabe en
todo momento el estado de la iteración, el iterador se encuentra en esta misma
clase, es decir que solo hay uno por cada objeto, es decir que no puede seer
utilizado en procesos concurrentes o por otros objetos que puedan utilizar la
iteración al mismo tiempo.
El segundo enfoque de este patrón es el Iterador Externo, de esta forma la
funcionalidad del Iterador se separa de la clase contenedora de la colección y se
delega a otra, trabajando con el ejemplo anterior se tienen las clases Candidate
y AllCandidates, pero ahora la clase AllCandidates no es la que implenta la
interfaz Iterador, esto lo hará la clase CertiedCandidates que además hará un
ltro especico (Certied), esta última clase se encargará de mantener el estado
del Iterador y proveer los métodos next() y hasNext(). La clase AllCandidates
provee los métodos getCertiedCandidates que retorna un nuevo objeto de la
clase CertiedCandidates en cada llamada y getAllCandidates que retorna un
objeto de la clase Enumeration que se obtiene del vector. Con este enfoque se
pueden obtener multiples Iteradores de una misma colección al mismo tiempo, al
mantener el estado de la iteración en una clase separada a la clase contenedora.

2.3. Flyweight

Este patrón de diseño busca optimizar recursos, la información puede ser


de dos tipos: intrínseca, la cual depende del contexto del objeto, es decir que
puede ser común para diferentes objetos de una misma clase. Extrínseca, que la
información que varia con el contexto del objeto, es decir que es única.

5
Ejemplo

Si se tiene una aplicación en la cual sea necesario una gran variedad de


objetos, los cuales pueden contener los dos tipos de información, la información
intrínseca tendría que ser creada y mantenida en cada uno de los objetos creados,
lo cual podría ser muy costoso en términos de optimización del uso de memoria.
El patrón de diseño yweight puede ser usado en este tipo de escenarios para
crear objetos mas ecientes.
Se sugiere que la información intrínseca que es común sea separada en un
objeto diferente, llamado Flyweight, el grupo de objetos que se crea comparte
el objeto Flyweight, eliminando asi la necesidad de almacenar en cada objeto la
información invariante.
Para implementar este patrón el objeto Flyweight debe ser un Singleton,
evitando que sea creado mas de una vez, además este debe ser creado en una
Factoria en este caso FlyweightFactory, la clase Flyweight debe estar dentro
de la clase FlyweightFactory de tal forma que esta pueda llamar el constructor
privado. De esta forma la factoria retorna el objeto Flyweight en caso de existir
sino lo crea y lo retorna. Existe además una interfaz FlyweightIntr que provee
métodos para obtener los valores intrínsecos que se encuentran en el objetos
Flyweight.
Existen dos enfoques en este patrón de diseño, los cuales se pueden usar de
acuerdo al entorno de la aplicación que se esta desarrollando. En el primero
supongamos que se tiene la clase Vcard, la cual tiene como atributos los valores
Extrínsecos y el objeto Flyweight,esta clase tiene un método print para mostrar
su contenido.
En el segundo enfoque no se crea una clase para almacenar los datos,simplemente
son enviados cuando son utilizados, es decir que el método print ahora esta en
la clase Flyweight, cuando este método es invocado recibe como parámetros la
información intrínseca y la muestra junto con la Extrínseca.

2.4. Visitador

EL patrón de diseño Visitador es útil en el diseño de una operación en una


colección heterogénea de objetos de una jerarquia de clases. Permite denir una
operación sin modicar la clase de los objetos en una colección. Sugiere denir
la operación en una clase denominada Visitor. Separando la operación de la
colección de objetos. Por cada nueva operación se crea una nueva clase Visitor.

Ejemplo

Se ha hecho una aplicación que permite denir operaciones en una colección


de objetos de diferentes objetos de la clase Order, Se presentan tres tipos de
órdenes:
Overseas order : Ordenes de paises fuera de los Estados Unidos. Se adiciona
evío y manejo.
California Order : Ordenes a entregar en California. Se adiciona impuesto.

6
Non-California order : Ordenes a entregar fuera de California, no aplica im-
puesto.
Para dar solución a este problema se crea una clase por cada tipo de or-
den, NonCaliforniaOrder, CaliforniaOrder, OversearOrder. Cada clase tie-
ne los atributos necesarios que representan los costos para cada orden, la clase
NonCaliforniaOrder tiene el atributo orderAmount y un método correspon-
diente para acceder al mismo, de igual forma la clase CaliforniaOrder tiene
los atributos additionalTax() y orderAmount y la clase OversearOrder tiene
los atributos orderAmount y additionalSH. Para que sea posible denir una
operación que calcule el costo total de la orden para todos los objetos teniendo
en cuenta que cada objeto tiene atributos diferentes se crea una interfaz Visitor.
La interfaz dene el método visit(OrderType), uno por cada tipo de orden. Se
crea una clase llamada OrderVisitor que realiza esta última interfaz, para cada
clase se dene el método correspondiente visit(), en el que se calcula el costo
total de cada orden.

3. Patrones Estructurales

3.1. Decorador

El patrón de diseño Decorador pertenece al grupo de patrones de comporta-


miento, permite agregar funcionalidad a una jerarquía de clases sin modicarlas.

Ejemplo

Se tiene una interfaz Logger con un método log, recibiendo como parámetro
una cadena de caracteres, hay dos clases que implementan dicha interfaz, la clase
ConsoleLogger que se encarga de mostrar el mensaje en consola con la llamada
al método log y la clase FileLogger que se encarga de escribir el mensaje en
un archivo cuando el método log es llamado, para la creación de un Logger se
LoggerFactory, que hace uso del patrón de diseño Factory
hace uso de la clase
Method, el mensaje que se envía al método log de estas clases es una cadena
de texto, pero ahora se desea que el mensaje pueda ser encriptado o etiquetado
con HTML, se crea entonces la clase LoggerDecorator, esta clase implementa
la interfaz Logger y mantiene un objeto concreto de dicha interfaz llamado
logger que debe ser pasado al Decorador antes de llamar al método log, el
objeto logger podría ser del tipo ConsoleLogger ó FileLogger. En el método
log de la clase LoggerDecorator se hace la llamada al método log del objeto
logger, para dar la posibilidad de  decorar el mensaje ahora se crean las clases
HTMLLogger y EncryptLogger que heredan de la clase LoggerDecorator, en el
método log de cada una de estas clases la cadena de caracteres es  decorada ,
en el primer caso con etiquetas HTML y en el segundo caso con un encriptado
sencillo, posteriormente se llama el método log a partir del objeto logger.
Cuándo un objeto cliente quiere decorar los mensajes de registro crea el
objeto Decorador y pasa el tipo de Logger que usará. Luego llama al método

7
log del Decorador pasando el mensaje.
El decorador funciona como un wrapper (en español, envolotor) de los objetos
de tipo Logger,

3.2. Cadena de Responsabilidades

Este patrón de diseño busca un bajo grado de acoplamiento entre los objetos
que hacen una solicitud y los objetos que la atienden. Cuando se tiene mas de
un objeto que puede atender una solicitud se sugiere que se pueda atender
secuencialmente con estos objetos formando una cadena. Cada objeto tiene una
referencia al objeto siguiente, el primer objeto decide a que objeto pasa y así
sucesivamente hasta llegar al nal.

Ejemplo

Consiste en la aprobación de una solicitud de compra, la cual según el monto


es aprobada por una persona de diferente cargo en una compañia, se tiene en-
tonces la clase abstracta PRHandler que dene las clases que podrán aprobar las
solicitudes de compra. Esta clase tiene un objeto nextHandler de su mismo tipo
representando el siguiente objeto que puede aprobar la solicitud, también dene
el método authorize que recibe como parámetro la solicitud de compra (Purcha-
seRequest) la cual se pretende aprobar. De esta clase heredan: BranchManager,
RegionalDirector, VicePresident y PresidentCOO, en orden de jerarquía menor
a mayor. Cada una de estas clases sobreescribe el método authorize en caso que
el monto de la solicitud es menor al límite de aprobación del cargo la solicitud
se aprueba de lo contrario se llama al método authorize pero ahora del objeto
nextHandler que se tiene.
La clase cliente PRManager crea una autorización y crea objetos por cada
uno de los cargos, posteriormente dene el orden en que se escalará la solici-
tud, el último en aprobar será el presidente, en caso que el monto exceda el
límite la solicitud no es aprobada. Tan pronto se dene la cadena la solicitud
se intenta aprobar con el primer objeto de la cadena que en este caso sera el
BranchManager.

3.3. Adaptador

Es patrón de diseño adaptador permite hacer la conversión de una interfaz


en otra, con el n de preservar la re-usabilidad de las clases. Generalmente los
clientes de una clase acceden a un servicio a través de una interfaz, en algunos
casos pueden existir clases que pueden ser útiles para otros clientes, pero la
interfaz que permite obtener sus servicios en algunos casos no es la que el cliente
espera, es por eso que la interfaz se debe convertir en otra. Existen dos formas
de implementar este patrón de diseño.

8
Ejemplo

Clase Adaptador:

Consiste en una clase que hereda de la clase adaptada, además realiza la interfaz
esperada por el cliente, de tal forma que está nueva clase Adaptador será la que
use el cliente, la cuál llama al método requerido internamente.
Se tiene una interfaz AddressValidator, la cual dene el método isValidAd-
dress, con el n de validar una dirección, existe la clase USAddress realiza dicha
interfaz, validando la dirección de los Estados Unidos, la clase CAAddress per-
mite validar las direcciones de Canadá, con la diferencia que lo hace a través del
método isValidCanadianAddr, la clase cliente es la clase Customer, en la que se
tiene una dirección con postal y el estado, los cuales deben ser validados según
el tipo de consumidor (Customer). La clase cliente debe tener un objeto que sea
una ejemplicación de una clase concreta que realice la interfaz AddressValida-
tor, el cual se obtiene con el método getValidator de la clase cliente.
Para lograr que la clase Customer pueda reutilizar el código de la clase
CAAddress se crea la clase CAAddressAdapter que hereda de la clase adaptada
(CAAddress) e implementa la interfaz AddressValidator, en el método isVali-
dAddress se hace el llamado al método isValidCanadianAddr logrando proveer
el servicio requerido por el cliente. De esta manera el cliente podrá acceder al
método a través de la interfaz AddressValidator sin importar el tipo de cliente.

Objeto Adaptador:

En este caso la clase Adaptador mantiene una referencia al objeto adaptado


e implementa la interfaz esperada por el cliente, cuándo se hace el llamado al
método el adaptador hace el llamado al método apropiado del objeto adaptado.
Al igual que en ejemplo de la clase Adaptador se tienen las clases, USAddress
y CAAddress que cumplen las mismas funciones, la diferencia es que el servicio
se provee a traves de la clase abstracta AddressValidator, que tiene el método
isValidAddress,la clase CAAddressAdapter que funciona como adaptador tiene
un objeto de la clase CAAddress, recibido en el constructor, el cual permitirá
llamar al método isValidCanadianAddr dinámicamente cuando se llama al mé-
todo isValidAddress. Así la clase Customer antes de crear el objeto adaptador
crea el objeto Adaptado.
La diferencia en los dos enfoques está en que el primero es estático y el
segundo dinámico, adicionalmente el segundo enfoque logra envolver el objeto
adaptado sin heredar el la clase adaptada.

3.4. Fachada

El patrón de diseño fachada realiza una negociación con un subsistema de


clases. Un subsistema es un conjunto de clases que trabajan con el propósito de
proveer un conjunto de características o funcionalidad. Generalmente los clien-
tes de un subsistema deben interactuar con un número de clase del subsistema
para cumplir con su objetivo. Este tipo de interacciones entre el cliente y el sub-
sistema lleva a un alto grado de acoplamiento entre estos. Cuando el subsistema

9
cambie, por ejemplo en una interfaz, los clientes deberán afrontar estos cambios.
El patrón Fachada es útil en este tipo de situaciones, provee un mayor nivel,
una interfaz simplicada de un subsistema que como resultado reduce la com-
plejidad y dependencia. De esta manera el subsistema es más fácil de manejar
y administrable.
Con este patrón no se deberían incluir nuevas funcionalidades, tampoco re-
tornar objetos cliente. Este patrón busca desacoplar el subsistema del cliente

Ejemplo:

Se presenta el diseño de una aplicación que recibe la información de un


cliente, cuenta, dirección y tarjeta de crédito. Está información debe ser validada
y almacenada en un chero. Esto se representa con las clases: Account, Address
y CreditCard en el orden respectivo. Cada una de estas clases tiene los métodos
apropiados para validar y almacenar la respectiva información. Este conjunto de
clases permite recibir la información del cliente, pero un objeto cliente debería
negociar con cada una de estas clases. La clase CustomerFacade permite agrupar
este conjunto de clases y presentarlo al cliente sin que este se entere de la
existencia de las clases que contiene, presentando los métodos apropiados para
Account, Address y
recibir la información del cliente y transmitirla a las clases
CreditCard. Adicionalmente se tiene el método saveCustomerData que permite
validar la información de cada una de las clases y almacenarla únicamente si
toda la información es valida, de lo contrario se retorna un mensaje de error.
Ahora se tiene la clase cliente AccountManager, está clase presenta una Ven-
tana al usuario solicitando la información del cliente, una vez diligenciada el
usuario intenta validar y almacenar la información, se crea un objeto de tipo
CustomerFacade, y se le envía la información de la cuenta, dirección y tarjeta de
crédito. Posteriormente se llama al método saveCustomerData que se encarga
de validar la información y si es correcta almacenarla.

3.5. Proxy

Generalmente cuando un objeto cliente quiere acceder a un servicio lo hace


a través de una llamada directa al objeto cliente, se pueden presentar casos en
los que un cliente no esté habilidatado para realizar el llamado a un servicio
directamente, debido a diferentes raazones, por ejemplo la ubicación del objeto
a invocar, el estado de existencia del objeto meta, comportamiento especiales
(seguridad). En estos casos el patrón de diseño pro xy busca evitar que el cliente
deba negociar con este tipo de requerimientos para acceder a un servicio. Se
sugiere entonces crear un objeto proxy encargado de presentar a los clientes un
medio para acceder al objeto requerido.
El objeto proxy presenta dos características importantes:

Es un intermediario entre el objeto cliente y el objeto objetivo.

Recibe las llamadas del objeto cliente y las envía al objeto objetivo.

10
Ejemplo:

Se toma como base el ejemplo del Patrón Fachada, pero ahora el almacena-
miento de la información no se debe hacer de forma local sino remota, por medio
del uso de RMI. Se diseña entonces una aplicación que representa el servidor y
Account, Address, Credit-
otra el cliente. En el servidor Se encuentran las clases
Card y CustomerFacade. La diferencia se presenta en esta última clase, ahora
se tiene la interfaz CustomerIntr que deberá ser realizada por la clase cliente y
por la clase CustomerFacade, está interfaz dene los mismo métodos que pre-
senta la clase CustomerFacade en el ejemplo anterior. La clase CustomerFacade
extiende de la clase UnicastRemoteObject del paquete de java.rmi de java, que
permite registrarlo como un objeto remoto y pueda ser accedida por el objeto
cliente.
La clase clienteAccountManager, también descrita en el patrón Fachada,
ahora no hace uso directo de la clase CustomerFacade, simplemente realiza la
interfaz CustomerIntr, luego se obtiene el objeto cliente buscando el servicio
en la red por medio de un nombre y dirección, el objeto CustomerFacade es
asignado a la clase cliente si el servidor es visible y accesible para el cliente,
nalmente el cliente accede al servicio de la misma manera en que lo hacia de
forma local.
En este ejemplo la implementación del proxy se encuentra en el objeto stub,
que se generado por el compilador de rmi (RMIC), en este caso el stub es gene-
rado del objeto CustomerFacade, permitiendo así que este objeto sea accedido
como si fuera de forma local y enviando la petición al servidor.

3.6. Bridge

El patrón Bridge (en español Puente ) promueve la separación de una inter-


faz de abstracción de su implementación. En general la abstracción se reere al
proceso de identicar un conjunto de atributos y comportamientos de un obje-
to que es especíco para un uso en particular. Una abstracción Este puede ser
diseñado como un objeto separado omitiendo sus atributos y comportamiento
irrelevantes.
Para este patrón se crea una interfaz que representa la abstracción que debe
tener una referencia a un objeto implementador, las abstracciones concretas
realizarán esta interfaz. Por otra parte se encuentra la interfaz implementador,
de la cual nace la jerarquía de implementadores. El cliente crea el objeto deseado
de la abstracción y lo congura con un objeto implementador.

Ejemplo:

Se ha diseñado una interfaz MessageLogger, con el método logMsg, que es


FileLogger, encargada de enviar un mensaje a un archivo
realizada por las clases
de registro y ConsoleLogger que muestra el mensaje en consola. Como se habla
en la descripción del patrón, estas son clases implementadoras, cumplen con la

11
funcionalidad de enviar un mensaje a un registro, ya sea la consola o un archivo
de texto plano.
Ahora se desea que esos mensajes puedan ser enviados en un formato dife-
rente, por ejemplo encriptado. Se podrían modicar las clases descritas anterior-
mente para cumplir con este requerimiento, pero se estaría violando el principio
básico de la orientación a objetos abierto para la extensión y cerrado para la
modicación.
Se dene entonces la interfaz Message con el método log, que representa
la abstracción, del mensaje que se registra, nacen entonces dos abstracciones
concretas, la clase EncryptedMessage y TextMessage, que realizan la interfaz
Message. Cada una de estas clases tiene una referencia a un objeto concre-
to de la interfaz MessageLogger, cuando el método log es llamado se hace un
pre-procesamiento del mensaje que se envía, en el caso de la clase EncryptedMes-
sage el mensaje es encriptado, en la clase TextMessage simplemente se retorna
el mismo mensaje. El cliente crea un objeto implementador, luego se crea la
abstracción y se congura con el objeto implementador, nalmente se envían
los mensajes directamente a la abstracción.

3.7. Aggregate Enforcer

En la orientación a objetos existe un tipo especial de asociación, se presenta


cuando un objeto denominado aggregate (en español agregado) contiene a otros
objetos como parte de este. Existen dos tipos, la agregación se presenta cuando
las partes que constituyen el aggregate pueden existir sin este. El otro tipo de
asociación es la composición, este tipo es más fuerte, los objetos que conforman
el aggregate no pueden existir sin el objeto agregado.
Los objetos que hacen parte del objeto constituido se pueden inicializar ya
sea en el tiempo de creación del objeto aggregate (inicialización temprana) o
bajo demanda cuando el objeto es necesitado.

Ejemplo:

Computer
En el ejemplo se consideran tres enfoques, consiste en una clase
que es el objetoaggregate conformado por un objeto de la clase CPU. En la
clase Computer se encuentra el método initCPU donde es necesario que la clase
cpu este inicializada.

Enfoque Uno (Inicialización Bajo Demanda):

El objeto se crea solo cuando es requerido, es decir cuando se hace un llamado


al método initCPU, se verica la variable cpu, si es nula entonces se inicializa.

Enfoque Dos (Inicialización Temprana):

El objeto de la clase CPU se crea con el constructor de la clase Computer. Eli-


minando así la necesidad de vericar si el objeto es nulo, aunque no es requerido
absolutamente crear el objeto CPU para crear el objeto global Computer. En

12
general se necesita una forma de hacer mandatario el hecho de inicializar el con-
junto de variables que representan el objeto que constituye el objeto aggregate.

Enfoque Tres (Variables Final ):

La variable cpu en la clase Computer es declarada como nal, así el compilador


de Java obliga que esta variable sea inicializada en el constructor de la clase.

4. Patrones Comportamentales

4.1. Comando

En la programación orientada a objetos las aplicaciones están basadas en


la interacción entre objetos, la cual suele ser limitada. Para dar respuesta al
usuario la aplicación debe hacer algún tipo de procesamiento, esta se puede dar
a través de un objeto que invoca operaciones de otros objetos. En este punto
se puede llegar a presentar un alto grado acoplamiento si el objeto que invoca
tiene que decidir que objeto debe procesar una petición.
El patrón de diseño Comando busca que al llamar una operación de un objeto
no se conozca el contenido de esta, por lo que se propone una abstracción para
el procesamiento de la petición hecha por el cliente. Cada operación es llevada
a una clase concreta.

Ejemplo:

Se presenta una clase principal FTPGUI, esta es una ventana que contie-
ne una lista representando archivos locales y una lista representando archi-
vos remotos, existen cuatro acciones para el usuario Upload, Download, Delete,
Exit. La opción Upload permite trasladar un archivo de la lista local a la lis-
ta remota, la opción Download permite llevar un archivo de la lista Remota
a la local, con Delete se elimina el archivo seleccionado, la opción Exit na-
liza la aplicación. La abstracción que representa las operaciones es la interfaz
CommandInterface con el método processEvent(). Cada una de las acciones
es llevada a una clase concreta que realiza esta interfaz y además hereda de
la clase JButton, de esta forma se agregan a la ventana principal, en el méto-
do processEvent() se realizaran las operaciones que correspondan, las clases
creadas son UploadButton, DownloadButton, DeleteButton y ExitButton. Se
tiene la clase buttonHandler que realiza la interfaz ActionListener con el n
de saber en que momento de selecciona una de las acciones.
En el momento que el usuario selecciona una acción la petición es enviada a la
clase buttonHandler por medio del método actionPerformed (), este método
recibe como parámetro el botón que fue seleccionado, gracias a que todos los
botones realizan la interfaz CommandInterface se llama directamente el método
processEvent(), se envía la petición directamente al botón correspondiente sin
tener la necesidad de identicar cual fue seleccionado.

13
4.2. Mediador

Es común encontrar interacciones entre objetos comunicándose entre sí,


cuando existen varios objetos que se comunican directamente se aumenta la
complejidad de las referencias entre objetos. En estos casos el patrón de diseño
Mediador se puede utilizar con el n de realizar un modelo de comunicación
controlada y coordinada entre un grupo de objetos, eliminando la necesidad de
que un objeto tenga referencias a otros. Este patrón propone una abstracción
de la interacción de los objetos en una clase Mediador, teniendo el conocimiento
de la interacción entre los objetos. Ahora los objetos envían los mensajes al
mediador y este los redirige a los objetos correspondientes.

Ejemplo:

Se trabaja con el mismo ejemplo del patrón Comando, ahora se desea desha-
bilitar las opciones de acuerdo a la selección del usuario o a la acción ejecutada,
si el usuario selecciona un archivo de la lista local la opciónDownload es des-
habilitada y los items de la lista remota no pueden estar seleccionados. En caso
que la selección sea hecha en la lista Remota, la opción Upload es deshabilitada
y los items de la lista local no pueden estar seleccionados. Se agrega ahora la
Mediator con una referencia a los objetos que son botones UploadButton,
clase
DownloadButton, DeleteButton y a las listas LocalList, RemoteList. Para
que el mediador pueda recibir estos objetos se crea un método para registrar
cada uno de estos, en el caso de un objeto de la clase UploadButton el méto-
do correspondiente es registerUploadButton(), de igual manera para todos los
objetos que se encuentran en el mediador.
Por cada uno de los objetos se crea un método debido a que a cada uno
le corresponde una acción por el usuario, para el botón UploadButton se crea
el método UploadItem(), en este caso se dene que archivo se debe tomar
de la lista local y enviarlo a la lista remota, nalmente todos los botones son
deshabilitados debido a que ningún archivo queda seleccionado.

4.3. Memento

El estado de un objeto se puede denir como los valores de los atributos


de un objeto en un punto del tiempo. El patrón de diseño memento permite
capturar y almacenar el estado de un objeto. Cuando es necesario, el objeto es
regresado a su estado anterior. Este patrón permite llevar a cabo esta operación
sin exponer la estructura interna del objeto. EL objeto del cual se obtiene el
estado se denomina Originator (en español autor), cuando un cliente requiere
almacenar el estado de un objeto, se solicita el estado actual al Originator y se
almacenan en un objeto separado denido como Memento.

Ejemplo:

El objetivo de la aplicación es convertir los datos de algunos clientes que se


encuentran en un archivo plano a sentencias sql. Se tiene la clase DataConverter

14
encargada de procesar la información en el método process(), se lee y valida
la información por cada cliente, cuando se presente un error en la validación se
debe almacenar el ID del último cliente leído. La clase Memento tiene el atributo
lastProcessedID y realiza la interfaz Serializable que permite almacenar
este objeto en un archivo. Al iniciar la aplicación una ejemplicación de la clase
MementoHandler lee del archivo ID el objeto memento si el archivo es encon-
trado. Posteriormente se crea el objeto objConverter de la clase DataConverter
y se le pasa el objeto memento leído, si no es nulo se almacena el id del objeto
memento en la variable ID de la clase DataConverter (ID es cero por defecto).
Al llamar el método process(), se verica que el último ID leído sea menor al
que se lee del archivo, si es así se crea un objeto de la clase Customer con la
información leída, se realiza la validación para convertirla a una sentencia sql
y se almacena, si el ID es mayor al id leído del archivo se lee otro cliente. En
caso de encontrarse información que no es valida se naliza el método process()
retornando estado de error, en este caso se solicita a la clase DataConverter
un objeto Memento con el estado actual, el objeto de la clase MementoHandler
almacena el objeto Memento al archivo ID y notica al usuario que existe un
error en la información de los clientes, solicitando que sea corregido. Así cuando
el proceso es reiniciado se continua con el ID que tenia error.

4.4. Observer

El patrón de diseño observador es útil para diseñar una comunicación consis-


tente entre un grupo de objetos dependientes y un objeto del que estos dependen.
Así el estado del grupo de objetos se mantiene sincronizado de acuerdo al objeto
del cual dependen. El conjunto de objetos dependientes de denomina observado-
res y el objeto del cual dependen se denomina sujeto. Para lograr esto se sugiere
un modelo publisher-subscriber (en español publicador-suscriptor), deniendo
así un límite claro entre el publicador y el suscriptor.

Ejemplo:

La aplicación consiste en una primera ventana en la que el usuario selecciona


un departamento de su interés (clase ReportManager), otra ventana que muestra
las transacciones del mes actual (clase MonthlyReport) y una tercera ventana
que muestra un reporte gráco de todas las transacciones del departamento
(clase YTDChart). EL patrón observador propone una interfaz Observable con
el método notifyObservers() que se encarga de noticar a los observadores un
cambio de estado y es realizada por el sujeto que en este caso es ReportManager,
para registrar los observadores se dene el método register() en esta misma
interfaz. Para los observadores MonthlyReport y YTDChart se dene una in-
terfaz Observer con el método refreshData() que recibe como parámetro el
sujeto. En el momento que el usuario selecciona un departamento en la clase
ReportManager se hace una llamada al método refreshData() de todos los
observadores. La ventana MonthlyReport lee la información del mes actual de

15
acuerdo al departamento seleccionado en el sujeto, la ventana YTDChart muestra
el gráco correspondiente también al departamento seleccionado del sujeto.

4.5. Interpreter

Generalmente los lenguajes son un conjunto de reglas gramaticales. Dife-


rentes oraciones pueden ser construidas siguiendo este conjunto de reglas. En
algunos casos las aplicaciones necesitan procesar solicitudes similares que son la
combinación de un conjunto de reglas gramaticales. Un ejemplo es un conjunto
de expresiones aritméticas que son enviadas a una calculadora. En estos casos
es conveniente que la aplicación sea capaz de interpretar una combinación de
reglas gramaticales genérica.

Ejemplo:

Se ha diseñado una calculadora con la capacidad de evaluar tres operaciones


básicas (+ − ×), se tiene la clase Context que representa un escenario particular
de la operación a ejecutar, en este caso almacena los valores de las variables
que se van a evaluar. La clase Calculator se encarga de recibir una expresión
matemática (In-ja) y un objeto de la clase Context, nalmente se evalua la
expresión matemática. Para evaluar esta expresión matemática es necesario con-
vertir la expresión in-ja a pos-ja, para esto se desarrolla un algoritmo en la
clase Calculator que se implementa en el método infixToPostFix(), poste-
riormente la expresión in-ja es llevada a un árbol binario. El árbol tiene dos
tipos de nodos, terminales y no terminales. Los nodos no terminales realizan
la operación que estos representan, por ejemplo la suma. Los nodos termina-
les representan una variable cuyo valor se encuentra en el objeto context, son
representados por la clase TerminalExpression. Para evaluar el árbol binario
que representa la expresión matemática se hace en orden pos-jo, es decir que
se evalúa primero el nodo de la izquierda, luego el de la derecha y nalmente se
realiza la operación indicada por el nodo retornando el resultado obtenido. La
clase NonTerminalExpression representa los nodos no terminales que puede
ser cualquiera de las tres operaciones, por este motivo es una clase abstrac-
ta, existe entonces una clase por cada operador matemático (AddExpression,
MultiplyExpression, SubtractExpression). Para evaluar toda la expresión mate-
mática se inicia por el nodo raíz, el cual recursivamente evalua todos los nodos
y nalmente retorna el resultado de la expresión.

4.6. State

El estado de un objeto se dene como su condición exacta en un punto del


tiempo, dependiendo de los valores de sus atributos. El conjunto de métodos
implementados en una clase denen el comportamiento de sus objetos. Cuando
el valor de un atributo cambia, el estado del objeto tiene un cambio. Un objeto
puede tener diferentes comportamiento según su estado. Este patrón de diseño
sugiere llevar el comportamiento particular de cada estado a una clase particular.

16
Ejemplo:

La aplicación simula la cuenta de un banco que es representada en la cla-


se BusinessAccount, está clase representa el contexto ya que tiene el atributo
balance, el cual almacena el valor que hay en la cuenta (puede ser negativo),
según esto se determinan los posibles estados de la cuenta. El primer estado es
Sin Cuota de Manejo (en inglés No transaction fee), que se da cuando el balan-
ce de la cuenta es mayor a 2000. El segundo estado es Con Cuota de Manejo
(en inglés Transaction fee state), se presenta si el balance es menor de 2000 o
mayor a 0. El tercer estado es Sobre-girado, si el balance es menor a 0. Se tiene
la clase State, esta clase dene un grupo de métodos que permiten manejar la
cuenta, entre los que se encuentran, InitialState() que dene el estado Inicial
(por defecto es NoTransactionFeeState), deposit() representa un deposito en la
cuenta y withdraw() que representa un retiro. Cuando se hace un deposito o un
retiro entonces se debe denir el nuevo estado de la cuenta. Por cada estado de
cuenta se dene una clase, NoTransactionFeeState, TransactionFeeState y Over-
DrawnState, estas clases heredan de la clase State sobre-escribiendo los métodos
deposit(), withdraw() y transitionState(), la cuenta tiene una referencia a
un objeto de la clase State (objState) sobre el cual se hace la operación co-
rrespondiente de deposito o retiro según la selección del usuario. La clase State
también tiene un objeto referencia de la clase BusinessAccount, que es denomi-
nado context debido a que esta representa el estado de la cuenta, de acuerdo al
estado que este presente, el objetoState puede ser cambiado (por ejemplo una
cuenta puede pasar de estar sobre-girada a estar sin cuota de manejo) gracias
al método transitionState().

4.7. Strategy

Este patrón de diseño es útil cuando se tiene un conjunto de algoritmos re-


lacionados y un cliente necesita tener la posiblidad de acceder a cualquiera de
estos de forma dinámica según su necesidad. Se sugiere mantener la implemen-
tación de cada algoritmo en una clase separada. El algoritmo se encapsula en
una clase que se denomina estrategia, el objeto que lo usa se denomina contexto.
Para permitir que el objeto contexto acceda a cualquiera de los algoritmos, estos
deben ser diseñados para presentar la misma interfaz.

Ejemplo

Se presenta una pequeña aplicación que permite enviar un mensaje a un


archivo de registro (en inglés log ), la clase encargada es FileLogger por me-
dio del método log(). La aplicación busca enviar este mensaje encriptado, pa-
ra lo cual existe una gran variedad de algoritmos, en este caso se han tomado
cuatro algoritmos de encriptación sencillos (SimpleEncryption,CaesarCypher,
SubstitutionCypher, CodeBookCypher). Se dene la interfaz EncryptionStrategy
con el método encrypt(), por cada uno de los algoritmos nombrados anterior-
mente se crea un clase que realiza esta interfaz, en el método encrypt() se

17
implementa el algoritmo de cada uno de estos métodos. El contexto en este caso
es representado por la clase EncryptLogger, el cual tiene un objeto que realice
EncryptionStrategy, este objeto puede ser cambiado con el método
la interfaz
setEncryptionStrategy(), tiene una referencia a un objeto FileLogger, y un
método log() para enviar el mensaje al archivo, que al ser llamado encripta
el mensaje y lo registra. La clase LoggerClient es la clase cliente, la cual crea
inicialmente el contexto, puede enviar un mensaje al registro o puede cambiar
el algoritmo dinamicamente.

4.8. Template Method

Este patrón de diseño permite es usado cuando un algoritmo que sigue una
serie de pasos, puede ser implementado siguiendo diferentes caminos. Se sugie-
re que el esquema del algoritmo se encuentre en un método separado que se
denomina método plantilla, en una clase que se plantilla, dejando la libre la im-
plementación de cada uno de los pasos del algoritmo. Aunque no es necesario
dejar todos los pasos a la implementación

Ejemplo

La aplicación busca validar la información de una tarjeta de crédito, se de-


nen tres tipos. Para llevar a cabo la validación se sigue una serie de validaciones
que aplican a cualquier tipo de tarjeta de crédito. Se dene la clase abstracta
CreditCard con el método isValid(), en el cual se hace el llamado de otros mé-
todo implementados en la clase, en este caso el método es final, para evitar que
las sub-clases lo sobre-escriban, esto podría no ser útil en caso que el orden o los
pasos de la validación cambiara. Los métodos llamados se encuentran en la mis-
ma clase, algunos son abstractos (isNumOfDigitsValid(), isValidPrefix()),
y otros ya se encuentran implementados, públicos (isExpDtValid()) y priva-
dos (hasValidChars(), isValidCheckSum()). De esta clase se crea una clase
concreta por cada tipo de tarjeta de crédito, que son DinersCard, MasterCard
y VisaCard, estas clases implementan los métodos abstractos. La clase cliente
mantiene una referencia a un objeto concreto de la clase CreditCard, llamando
su método isValid().

5. Patrones Concurrentes

5.1. Critical Section

Una sección crítica es un segemento de código que solo puede ser ejecutado
en un hilo a la vez. Cuando dos objetos intentan ejecutar este segmento de
código al mismo tiempo, esto puede llevar a resultados inesperados.

Ejemplo

Sección Crítica:

18
Se tiene una clase FileLogger que permite enviar un mensaje a un archivo de
registro plano (en inglés log ), en la aplicación solo se debe poder crear un objeto
logger cada vez, por lo que se ha implementado el patrón Singleton, el méto-
do getFileLogger() permite obtener un objeto único de la clase FileLogger,
que se almacena en el atributo logger. Pensando en una aplicación que pueda
acceder a este método concurrentemente la creación del objeto se introduce en
una sección crítica que se logra al agregar la palabra synchronized, del lenguaje
de programación java, a la denición del método getFileLogger() asegurando
de esta forma que solo un hilo puede acceder a este método al tiempo.

Inicialización Temprana:

Debido a que los métodos sincronizados en java pueden afectar el rendimiento


de la aplicación, se propone una creación temprana del objeto logger. El objeto
es inicializado desde su declaración global.

5.2. Consistent Lock Order

Cuando se crea una sección crítica solo se esta asegurando que dos objetos
cliente no hagan el llamado a un método en un mismo instante del tiempo,
se puede presentar el caso en el que un hilo mantiene bloqueado un objeto y
estan a la espera de un objeto que mantiene bloqueado otro hilo. Los dos hilos
permanecen esperando por siempre y se dice que han caido en un iterbloqueo
(en inglés deadlock ).

Ejemplo

Se tiene la clase FileSysUtil con el método moveContents() que recibe


como parámetros un directorio de origen y un directorio de destino, el método
deberia copiar los archivos del directorio origen al destino, por lo que debe blo-
quear ambos directorios, para evitar el interbloqueo se debe denir un orden de
bloqueo que sea siempre el mismo, para esto se hace uso del método hashCode()
propio de java, el cual retorna un número de identicación del objeto, que es
único, este número se obtiene para el directorio de destino y origen, siendo com-
parado. El directorio que tenga el número mayor de identicación es bloqueado
primero y posteriormente el otro, para nalmente ejecutar las operaciones de
copiado.

5.3. Guarded Suspension

Algunas veces un método es diseñado para llevar a cabo una funcionalidad


especíca, adicionalmente puede ser necesario que el objeto se encuentre en un
estado particular, en estos casos se sugiere que el método suspenda su ejecución
hasta que su estado sea el correcto.

19
Ejemplo

La aplicación simula un parqueadero en el que un carro llega, si hay cupo


puede parquear, de lo contrario debe esperar a que un carro salga. El par-
queadero es representado por la clase ParkingLot, el cual. tiene las variables
MAX_CAPACITY, que determina la capacidad máxima y totalParkedCars que
almacena el número de carros en el parqueadero. El método park() hace el par-
queo de uno de los clientes si hay cupo, es decir que el total de carro debe no
exceder la capacidad máxima, si no es así el método cae en un ciclo vercan-
do esta condición, dentro de este se hace un llamado al método wait(), propio
del lenguaje java, el cual obliga a esperar a que se haga el llamado al método
notify() ó notifyAl(). Al salir del ciclo, es decir si hay cupo, se incrementa la
variable totalParkedCars. El método leave se llama cuando un carro abandona
el parqueadero, la variable totalParkedCars se disminuye y se hace el llamado
al método notify().

5.4. Read-Write Lock

En las aplicaciones concurrentes es común que varios objetos intenten acceder


a un recurso simultaneamente. En estos casos el recurso se debe bloquear para
su acceso, algunos hilos pueden acceder solo para leer los valores o el estado del
recurso, por lo cual debería existir la posiblidad que varios hilos hagan lectura
pero no escritura sobre un objeto al mismo tiempo.

Ejemplo

Se tiene la clase Item que representa un artículo de una biblioteca, se en-


cuentra el método checkOut() que representa el retiro de un artículo, el método
checkIn() representa la devolución de un artículo. Para bloquear estas opera-
ciones se tiene la clase ReadWriteLock encargada de bloquear a los objetos que
estan intentando leer, el método getWriteLock() permite que solo un objeto
pueda acceder al artículo, evitando que se haga lectura hasta que el método
done() sea llamado. El método getStatus() de la clase Item permite conocer
el estado del artículo, en este caso se llama el método getReadLock() de la cla-
se ReadWriteLock. En este último se debe asegurar que no se este llevando a
cabo una operación de escritura. Para lograr que cada método permanezaca en
espera se utiliza un objeto lockObj, sobre el cual se llaman los métodos wait()
y notifyAll(), evitando así que deba sincronizarse un método en general sino
solo para el caso en que se cumplan las condiciones indicadas.
.

20

También podría gustarte