Design Patterns Es
Design Patterns Es
#design-
patterns
Tabla de contenido
Acerca de 1
Observaciones 2
Examples 2
Introducción 2
Capítulo 2: Adaptador 4
Examples 4
Adaptador (Java) 4
Ejemplo de Java 5
Examples 11
Introducción 13
Examples 13
Capítulo 5: Fábrica 15
Observaciones 15
Examples 15
Método de fábrica 26
Capítulo 6: Fachada 27
Examples 27
Fachada del mundo real (C #) 27
Introducción 31
Observaciones 31
Examples 32
Inyección de Setter (C #) 32
Inyección Constructor (C #) 32
Examples 34
Examples 37
Observaciones 41
Examples 41
El Patrón de Monostato 41
Observaciones 44
Examples 44
Observaciones 47
Examples 47
Observaciones 52
Examples 52
Observador / Java 52
Examples 56
Maderero compuesto 56
Introducción 58
Observaciones 58
Examples 58
Examples 60
Observaciones 63
Examples 63
Java / Lombok 69
Examples 73
Examples 76
Estrategia (PHP) 82
Examples 84
El patrón iterador 84
Observaciones 86
Examples 86
Examples 89
Observaciones 92
Examples 92
Las interfaces 92
Examples 96
Introducción 104
Parámetros 104
Examples 104
VendingMachineDecorator 104
Examples 110
Introducción 113
Observaciones 113
Examples 113
Examples 116
Muestra C # 116
Introducción 120
Observaciones 120
Examples 120
Examples 122
Observaciones 124
Examples 124
Singleton (C #) 124
Patrón Singleton seguro para hilos 124
Introducción 133
Examples 133
Creditos 138
Acerca de
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version
from: design-patterns
It is an unofficial and free Design patterns ebook created for educational purposes. All the content
is extracted from Stack Overflow Documentation, which is written by many hardworking individuals
at Stack Overflow. It is neither affiliated with Stack Overflow nor official Design patterns.
The content is released under Creative Commons BY-SA, and the list of contributors to each
chapter are provided in the credits section at the end of this book. Images may be copyright of
their respective owners unless otherwise specified. All trademarks and registered trademarks are
the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor
accurate, please send your feedback and corrections to [email protected]
https://riptutorial.com/es/home 1
Capítulo 1: Comenzando con los patrones de
diseño
Observaciones
Esta sección proporciona una descripción general de qué son los patrones de diseño y por qué un
desarrollador puede querer usarlo. Los ejemplos pueden proporcionar una representación gráfica
del patrón, un escenario que consiste en un problema dado un contexto en el que se puede usar
un patrón y mencionar posibles compensaciones.
También debe mencionar cualquier tema grande dentro de los patrones de diseño y vincular a los
temas relacionados. Dado que la Documentación para patrones de diseño es nueva, es posible
que deba crear versiones iniciales de esos temas relacionados.
Examples
Introducción
Según Wikipedia :
(Recuperado: 2016-10-13)
Hay muchos patrones de diseño de software reconocidos, y se proponen otros nuevos de forma
regular. Otros temas cubren muchos de los patrones más comunes, y el artículo de Wikipedia
proporciona una lista más extensa.
De manera similar, hay diferentes formas de clasificar los patrones de diseño, pero la clasificación
original es:
https://riptutorial.com/es/home 2
Finalmente, hay un concepto relacionado llamado patrón de arquitectura de software que se
describe como el análogo de los patrones de diseño aplicados a las arquitecturas de software.
https://riptutorial.com/es/home 3
Capítulo 2: Adaptador
Examples
Patrón Adaptador (PHP)
Un ejemplo del mundo real que utiliza un experimento científico en el que se realizan ciertas
rutinas en diferentes tipos de tejido. La clase contiene dos funciones por defecto para obtener el
tejido o la rutina por separado. En una versión posterior, lo adaptamos utilizando una nueva clase
para agregar una función que obtiene ambas. Esto significa que no hemos editado el código
original y, por lo tanto, no corremos ningún riesgo de romper nuestra clase existente (y no volver a
realizar la prueba).
class Experiment {
private $routine;
private $tissue;
function __construct($routine_in, $tissue_in) {
$this->routine = $routine_in;
$this->tissue = $tissue_in;
}
function getRoutine() {
return $this->routine;
}
function getTissue() {
return $this->tissue;
}
}
class ExperimentAdapter {
private $experiment;
function __construct(Experiment $experiment_in) {
$this->experiment = $experiment_in;
}
function getRoutineAndTissue() {
return $this->experiment->getTissue().' ('. $this->experiment->getRoutine().')';
}
}
Adaptador (Java)
Supongamos que en su base de código actual, existe MyLogger interfaz de MyLogger así:
interface MyLogger {
void logMessage(String message);
void logException(Throwable exception);
}
Ha decidido que desea usar un marco para controlar la conectividad Bluetooth de su aplicación.
https://riptutorial.com/es/home 4
Este marco contiene un BluetoothManager con el siguiente constructor:
class BluetoothManager {
private FrameworkLogger logger;
El BluetoothManager también acepta un registrador, ¡lo cual es genial! Sin embargo, espera un
registrador cuya interfaz fue definida por el marco y han usado la sobrecarga de métodos en lugar
de nombrar sus funciones de manera diferente:
interface FrameworkLogger {
void log(String message);
void log(Throwable exception);
}
@Override
public void log(String message) {
this.logger.logMessage(message);
}
@Override
public void log(Throwable exception) {
this.logger.logException(exception);
}
}
Al definir una clase de adaptador que implementa la interfaz de FrameworkLogger y acepta una
implementación de MyLogger , la funcionalidad se puede asignar entre las diferentes interfaces.
Ahora es posible usar el MyLogger BluetoothManager con todas las implementaciones de MyLogger
como:
Ejemplo de Java
https://riptutorial.com/es/home 5
Un gran ejemplo existente del patrón del adaptador se puede encontrar en las clases SWT
MouseListener y MouseAdapter .
Ahora imagine un escenario en el que está creando una UI y agregando estos oyentes, pero la
mayoría de las veces no le importa nada más que cuando se hace clic en algo (mouseUp). No
querrías estar constantemente creando implementaciones vacías:
obj.addMouseListener(new MouseListener() {
@Override
public void mouseDoubleClick(MouseEvent e) {
}
@Override
public void mouseDown(MouseEvent e) {
}
@Override
public void mouseUp(MouseEvent e) {
// Do the things
}
});
obj.addMouseListener(new MouseAdapter() {
@Override
public void mouseUp(MouseEvent e) {
// Do the things
}
});
https://riptutorial.com/es/home 6
Para hacer un uso del patrón de adaptador y el tipo de situación en la que se puede aplicar más
imaginable, aquí se ofrece un ejemplo pequeño, simple y muy concreto. No habrá ningún código
aquí, solo UML y una descripción de la situación de ejemplo y su problema. Es cierto que el
contenido UML está escrito como Java. (Bueno, el texto de la sugerencia decía "Los buenos
ejemplos son principalmente código", creo que los patrones de diseño son lo suficientemente
abstractos como para ser presentados de una manera diferente, también).
En general, el patrón de adaptador es una solución adecuada para una situación en la que tiene
interfaces incompatibles y ninguna de ellas puede reescribirse directamente.
Imagina que tienes un buen servicio de reparto de pizzas. Los clientes pueden realizar pedidos en
línea en su sitio web y usted tiene un sistema pequeño que utiliza una Pizza clase para
representar sus pizzas y calcular facturas, informes de impuestos y más. El precio de sus pizzas
se da como un solo entero que representa el precio en centavos (de la moneda de su elección).
Su servicio de entrega está funcionando muy bien, pero en algún momento ya no puede manejar
el creciente número de clientes por su cuenta, pero aún desea expandirse. Decide agregar sus
pizzas al menú de un gran servicio de entrega meta en línea. Ofrecen muchas comidas
diferentes, no solo pizzas, por lo que su sistema hace un mayor uso de la abstracción y tiene una
Interfaz IMeal representa las comidas junto con una clase de MoneyAmount representa el dinero.
MoneyAmount consta de dos enteros como entrada, uno para la cantidad (o alguna moneda
aleatoria) antes de la coma, y otro para la cantidad de centavos de 0 a 99 después de la coma;
https://riptutorial.com/es/home 7
Debido al hecho de que el precio de su Pizza es un solo entero que representa el precio total
como una cantidad de centavo (> 99), no es compatible con IMeal . Este es el punto en el que el
patrón del adaptador entra en juego: en caso de que requiera demasiado esfuerzo cambiar su
propio sistema o crear uno nuevo y tenga que implementar una interfaz incompatible, es posible
que desee aplicar el patrón del adaptador.
Ambos tienen en común que un adaptador ( PizzaAdapter ) funciona como algún tipo de traductor
entre la nueva interfaz y el adaptee ( Pizza en este ejemplo). El adaptador implementa la nueva
interfaz ( IMeal ) y luego hereda de Pizza y convierte su propio precio de un entero a dos
(adaptador de clase)
https://riptutorial.com/es/home 8
o tiene un objeto de tipo Pizza como atributo y convierte los valores de ese (adaptador de objeto).
https://riptutorial.com/es/home 9
Al aplicar el patrón de adaptador, usted podrá "traducir" entre interfaces incompatibles.
https://riptutorial.com/es/home 10
Capítulo 3: Cadena de responsabilidad
Examples
Cadena de responsabilidad ejemplo (php)
Un método llamado en un objeto subirá la cadena de objetos hasta que se encuentre uno que
pueda manejar la llamada correctamente. Este ejemplo particular utiliza experimentos científicos
con funciones que solo pueden obtener el título del experimento, la identificación de los
experimentos o el tejido utilizado en el experimento.
https://riptutorial.com/es/home 11
return $this->parentExperiment->getTissue();
}
}
}
//This class and all further sub classes work in the same way as SubExperiment above
class SubSubExperiment extends AbstractExperiment {
private $experiment;
private $parentExperiment;
private $tissue;
function __construct($experiment_in, Experiment $parentExperiment_in) { //as above }
function getExperiment() { //same as above }
function getParentExperiment() { //same as above }
function getTissue() { //same as above }
}
https://riptutorial.com/es/home 12
Capítulo 4: carga lenta
Introducción
la carga impaciente es costosa o el objeto a cargar podría no ser necesario en absoluto
Examples
JAVA carga perezosa
Clase pesada
/**
*
* Heavy objects are expensive to create.
*
*/
public class Heavy {
/**
* Constructor
*/
public Heavy() {
LOGGER.info("Creating Heavy ...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
LOGGER.error("Exception caught.", e);
}
LOGGER.info("... Heavy created");
}
}
HolderNaive.class
/**
*
* Simple implementation of the lazy loading idiom. However, this is not thread safe.
*
*/
public class HolderNaive {
https://riptutorial.com/es/home 13
private Heavy heavy;
/**
* Constructor
*/
public HolderNaive() {
LOGGER.info("HolderNaive created");
}
/**
* Get heavy object
*/
public Heavy getHeavy() {
if (heavy == null) {
heavy = new Heavy();
}
return heavy;
}
}
https://riptutorial.com/es/home 14
Capítulo 5: Fábrica
Observaciones
Proporcionar una interfaz para crear familias de objetos relacionados o dependientes
sin especificar sus clases concretas.
- GOF 1994
Examples
Fábrica simple (Java)
Una fábrica reduce el acoplamiento entre el código que necesita crear objetos a partir del código
de creación de objetos. La creación de objetos no se hace explícitamente llamando a un
constructor de clase, sino llamando a alguna función que crea el objeto en nombre del llamante.
Un ejemplo simple de Java es el siguiente:
interface Car {
}
https://riptutorial.com/es/home 15
En este ejemplo, el usuario solo da una pista sobre lo que necesita y la fábrica es libre de
construir algo apropiado. Es una inversión de dependencia : el implementador del concepto de
Car es libre de devolver un Car concreto apropiado solicitado por el usuario que a su vez no
conoce los detalles del objeto concreto construido.
Este es un ejemplo simple de cómo funciona la fábrica; por supuesto, en este ejemplo, siempre es
posible instanciar clases concretas; pero uno puede evitarlo ocultando clases concretas en un
paquete, de manera que el usuario se vea obligado a usar la fábrica.
El patrón abstracto de fábrica proporciona una manera de obtener una colección coherente de
objetos a través de una colección de funciones de fábricas. En cuanto a cada patrón, el
acoplamiento se reduce al abstraer la forma en que se crea un conjunto de objetos, de modo que
el código de usuario no es consciente de los muchos detalles de los objetos que necesita.
El siguiente ejemplo de C ++ ilustra cómo obtener diferentes tipos de objetos de la misma familia
de GUI (hipotética):
#include <iostream>
/* Abstract definitions */
class GUIComponent {
public:
virtual ~GUIComponent() = default;
virtual void draw() const = 0;
};
class Frame : public GUIComponent {};
class Button : public GUIComponent {};
class Label : public GUIComponent {};
class GUIFactory {
public:
virtual ~GUIFactory() = default;
virtual std::unique_ptr<Frame> createFrame() = 0;
virtual std::unique_ptr<Button> createButton() = 0;
virtual std::unique_ptr<Label> createLabel() = 0;
static std::unique_ptr<GUIFactory> create(const std::string& type);
};
/* Windows support */
class WindowsFactory : public GUIFactory {
private:
class WindowsFrame : public Frame {
public:
void draw() const override { std::cout << "I'm a Windows-like frame" << std::endl; }
};
class WindowsButton : public Button {
public:
void draw() const override { std::cout << "I'm a Windows-like button" << std::endl; }
};
class WindowsLabel : public Label {
public:
https://riptutorial.com/es/home 16
void draw() const override { std::cout << "I'm a Windows-like label" << std::endl; }
};
public:
std::unique_ptr<Frame> createFrame() override { return std::make_unique<WindowsFrame>(); }
std::unique_ptr<Button> createButton() override { return std::make_unique<WindowsButton>();
}
std::unique_ptr<Label> createLabel() override { return std::make_unique<WindowsLabel>(); }
};
/* Linux support */
class LinuxFactory : public GUIFactory {
private:
class LinuxFrame : public Frame {
public:
void draw() const override { std::cout << "I'm a Linux-like frame" << std::endl; }
};
class LinuxButton : public Button {
public:
void draw() const override { std::cout << "I'm a Linux-like button" << std::endl; }
};
class LinuxLabel : public Label {
public:
void draw() const override { std::cout << "I'm a Linux-like label" << std::endl; }
};
public:
std::unique_ptr<Frame> createFrame() override { return std::make_unique<LinuxFrame>(); }
std::unique_ptr<Button> createButton() override { return std::make_unique<LinuxButton>(); }
std::unique_ptr<Label> createLabel() override { return std::make_unique<LinuxLabel>(); }
};
/* User code */
void buildInterface(GUIFactory& factory) {
auto frame = factory.createFrame();
auto button = factory.createButton();
auto label = factory.createLabel();
frame->draw();
button->draw();
label->draw();
}
$ ./abstractfactory windows
I'm a Windows-like frame
I'm a Windows-like button
I'm a Windows-like label
$ ./abstractfactory linux
I'm a Linux-like frame
https://riptutorial.com/es/home 17
I'm a Linux-like button
I'm a Linux-like label
Las fábricas también se pueden utilizar junto con las bibliotecas de Inversión de control (IoC).
• El caso de uso típico de una fábrica de este tipo es cuando queremos crear un objeto
basado en parámetros que no se conocen hasta el tiempo de ejecución (como el usuario
actual).
• En estos casos, a veces puede ser difícil (si no imposible) configurar la biblioteca IoC sola
para manejar este tipo de información contextual en tiempo de ejecución, por lo que
podemos envolverla en una fábrica.
Ejemplo
• Supongamos que tenemos una clase de User , cuyas características (ID, nivel de
autorización de seguridad, etc.) se desconocen hasta el tiempo de ejecución (ya que el
usuario actual podría ser cualquiera que use la aplicación).
• Necesitamos tomar el Usuario actual y obtener un ISecurityToken para ellos, que luego se
puede usar para verificar si el usuario tiene permiso para realizar ciertas acciones o no.
• La implementación de ISecurityToken variará dependiendo del nivel del Usuario; en otras
palabras, ISecurityToken usa polimorfismo .
En este caso, tenemos dos implementaciones, que también utilizan interfaces de marcador para
facilitar su identificación en la biblioteca IoC; La biblioteca IoC en este caso solo está formada e
identificada por la abstracción IContainer .
Tenga en cuenta también que muchas fábricas modernas de IoC tienen capacidades o
complementos nativos que permiten la creación automática de fábricas, además de
evitar la necesidad de interfaces de marcador como se muestra a continuación; sin
embargo, como no todos lo hacen, este ejemplo se adapta a un concepto de
funcionalidad común más simple y más bajo.
https://riptutorial.com/es/home 18
return true;
}
}
el código consumidor puede usarlo para obtener el token correcto en tiempo de ejecución:
https://riptutorial.com/es/home 19
}
Se utiliza una fábrica abstracta para proporcionar una interfaz para crear familias de objetos
relacionados, sin especificar clases concretas y se puede usar para ocultar clases específicas de
la plataforma.
interface Tool {
void use();
}
interface ToolFactory {
Tool create();
}
@Override
public void use() {
// Do something...
}
}
@Override
public Tool create() {
// Maybe additional logic to setup...
return new GardenTool();
https://riptutorial.com/es/home 20
}
}
@Override
public void use() {
// Do something...
}
}
@Override
public Tool create() {
// Maybe additional logic to setup...
return new FarmTool();
}
}
Luego, se usaría un proveedor / productor de algún tipo al que se le pasaría información que le
permitiría devolver el tipo correcto de implementación de fábrica:
switch (type) {
case FARM:
factory = new FarmToolFactory();
break;
case GARDEN:
factory = new GardenToolFactory();
break;
} // Could potentially add a default case to handle someone passing in null
return factory;
}
}
Intención:
Defina una interfaz para crear un objeto, pero deje que las subclases decidan qué clase crear una
instancia. Método de fábrica permite que una clase difiera la creación de instancias a subclases.
https://riptutorial.com/es/home 21
Diagrama UML:
Producto: Define una interfaz de los objetos que crea el método Factory.
Declaración de problema: cree una Factory of Games usando Factory Methods, que define la
interfaz del juego.
Fragmento de código:
import java.util.HashMap;
https://riptutorial.com/es/home 22
public void createGame(){
System.out.println("---------------------------------------");
System.out.println("Create Checkers game");
System.out.println("Opponents:2 or 3 or 4 or 6");
System.out.println("For each opponent, place 10 coins");
System.out.println("Start Checkers game");
System.out.println("---------------------------------------");
}
}
class Ludo implements Game{
public Ludo(){
createGame();
}
public void createGame(){
System.out.println("---------------------------------------");
System.out.println("Create Ludo game");
System.out.println("Opponents:2 or 3 or 4");
System.out.println("For each opponent, place 4 coins");
System.out.println("Create two dices with numbers from 1-6");
System.out.println("Start Ludo game");
System.out.println("---------------------------------------");
}
}
public GameFactory(){
games.put(Chess.class.getName(),new Chess());
games.put(Checkers.class.getName(),new Checkers());
games.put(Ludo.class.getName(),new Ludo());
}
public Game getGame(String gameName){
return games.get(gameName);
}
}
https://riptutorial.com/es/home 23
Game game = factory.getGame(args[0]);
System.out.println("Game="+game.getClass().getName());
}
}
salida:
1. Game es la interfaz para todo tipo de juegos. Se define el método complejo: createGame()
2. Chess, Ludo, Checkers son diferentes variantes de juegos, que proporcionan implementación
a createGame()
Cuándo usar:
https://riptutorial.com/es/home 24
3. Método de fábrica: para definir una interfaz para crear un objeto, pero deje que las
subclases decidan qué clase crear una instancia.
1. El diseño comienza con Factory Method (menos complicado, más personalizable, las
subclases proliferan) y evoluciona hacia Abstract Factory, Prototype o Builder (más
flexible, más complejo) a medida que el diseñador descubre dónde se necesita más
flexibilidad.
En palabras simples:
Una fábrica de peso mosca que para una clave dada, ya conocida, siempre dará el mismo objeto
como respuesta. Para las nuevas claves creará la instancia y la devolverá.
Usando la fábrica:
Implementación:
https://riptutorial.com/es/home 25
return result;
}
Notas adicionales
Recomendaría agregar a esta solución el uso de un IoC Container (como se explica en un ejemplo
diferente aquí) en lugar de crear sus propias nuevas instancias. Uno puede hacerlo agregando un
nuevo registro para el TResult al contenedor y luego resolviéndolo (en lugar del dictionary en el
ejemplo).
Método de fábrica
El patrón del método Factory es un patrón creacional que abstrae la lógica de creación de
instancias de un objeto para desacoplar el código del cliente.
Cuando un método de fábrica pertenece a una clase que es una implementación de otro patrón
de fábrica como Abstract factory , generalmente es más apropiado hacer referencia al patrón
implementado por esa clase en lugar del patrón de método Factory.
El patrón del método de fábrica es más comúnmente referenciado cuando se describe un método
de fábrica que pertenece a una clase que no es principalmente una fábrica.
Por ejemplo, puede ser ventajoso colocar un método de fábrica en un objeto que represente un
concepto de dominio si ese objeto encapsula algún estado que simplifique el proceso de creación
de otro objeto. Un método de fábrica también puede conducir a un diseño más alineado con el
lenguaje ubicuo de un contexto específico.
https://riptutorial.com/es/home 26
Capítulo 6: Fachada
Examples
Fachada del mundo real (C #)
facade.Execute();
}
}
// the facade puts all the individual pieces together, as its single responsibility.
public void Execute()
{
var dataLocationForExport = _determineExportData.GetDataLocation();
var rawData = _getRawData.GetDataFromDb(dataLocationForExport);
var transformedData = _transformData.TransformRawToExportableObject(rawData);
_createExcel.GenerateExcel("myFilename.xlsx");
}
}
Estructura:
https://riptutorial.com/es/home 27
Ejemplo del mundo real:
Piense en algunos sitios de reserva de viajes como makemytrip, cleartrip, que ofrece servicios
para reservar trenes, vuelos y hoteles.
Fragmento de código:
import java.util.*;
enum BookingType {
Flight,Train,Hotel,Flight_And_Hotel,Train_And_Hotel;
};
public TravelFacade(){
flightBooking = new FlightBooking();
trainBooking = new TrainBooking();
hotelBooking = new HotelBooking();
}
public void book(BookingType type, BookingInfo info){
switch(type){
case Flight:
// book flight;
flightBooking.bookFlight(info);
return;
case Hotel:
// book hotel;
hotelBooking.bookHotel(info);
return;
case Train:
// book Train;
https://riptutorial.com/es/home 28
trainBooking.bookTrain(info);
return;
case Flight_And_Hotel:
// book Flight and Hotel
flightBooking.bookFlight(info);
hotelBooking.bookHotel(info);
return;
case Train_And_Hotel:
// book Train and Hotel
trainBooking.bookTrain(info);
hotelBooking.bookHotel(info);
return;
}
}
}
class BookingInfo{
String source;
String destination;
Date fromDate;
Date toDate;
List<PersonInfo> list;
}
class PersonInfo{
String name;
int age;
Address address;
}
class Address{
}
class FlightBooking{
public FlightBooking(){
}
public void bookFlight(BookingInfo info){
}
}
class HotelBooking{
public HotelBooking(){
}
public void bookHotel(BookingInfo info){
}
}
class TrainBooking{
public TrainBooking(){
}
public void bookTrain(BookingInfo info){
}
}
Explicación:
https://riptutorial.com/es/home 29
2. TravelFacade ofrece una interfaz simple para reservar una de las siguientes opciones
Flight Booking
Train Booking
Hotel Booking
Flight + Hotel booking
Train + Hotel booking
3. API de libro de TravelFacade realiza llamadas internas por debajo de las API de los
subsistemas
flightBooking.bookFlight
trainBooking.bookTrain(info);
hotelBooking.bookHotel(info);
4. De esta manera, TravelFacade proporciona una API más simple y sencilla sin exponer las API
del subsistema.
https://riptutorial.com/es/home 30
Capítulo 7: Inyección de dependencia
Introducción
La idea general detrás de la inyección de dependencia es que usted diseña su aplicación en torno
a componentes débilmente acoplados mientras se adhiere al principio de inversión de
dependencia. Al no depender de implementaciones concretas, permite diseñar sistemas
altamente flexibles.
Observaciones
La idea básica detrás de la inyección de dependencia es crear un código acoplado de forma más
flexible. Cuando una clase, en lugar de crear sus propias dependencias, toma sus dependencias,
la clase se vuelve más sencilla de probar como una unidad ( prueba de unidad ).
Para profundizar más en el acoplamiento flexible, la idea es que las clases se vuelvan
dependientes de las abstracciones, en lugar de concreciones. Si la clase A depende de otra clase
concreta B , entonces no hay pruebas reales de A sin B Si bien este tipo de prueba puede estar
bien, no se presta al código de unidad comprobable. Un diseño débilmente acoplado definiría una
abstracción IB (como ejemplo) de la cual dependería la clase A IB puede ser burlado para
proporcionar un comportamiento comprobable, en lugar de confiar en la implementación real de B
para poder proporcionar escenarios comprobables a A
public class A
{
public void DoStuff()
{
B b = new B();
b.Foo();
}
}
En lo anterior, la clase A depende de B No hay pruebas A sin el hormigón B Si bien esto está bien
en un escenario de pruebas de integración, es difícil realizar A prueba unitaria A
public interface IB
{
void Foo();
}
public class A
{
private readonly IB _iB;
https://riptutorial.com/es/home 31
{
_iB = iB;
}
Las dos implementaciones parecen bastante similares, sin embargo hay una diferencia
importante. La clase A ya no depende directamente de la clase B , ahora depende de IB . La Clase
A ya no tiene la responsabilidad de renovar sus propias dependencias; ahora debe
proporcionarlas a A
Examples
Inyección de Setter (C #)
Inyección Constructor (C #)
https://riptutorial.com/es/home 32
}
https://riptutorial.com/es/home 33
Capítulo 8: Método de fábrica estático
Examples
Método de fábrica estática
Podemos proporcionar a varios constructores el mismo número y tipo de parámetros, algo que,
como vimos anteriormente, no podemos hacer con los constructores de clases.
Podemos evitar proporcionar acceso directo a constructores que hacen un uso intensivo de
recursos, como para bases de datos. clase pública DbConnection {private static final int
MAX_CONNS = 100; private static int totalConnections = 0;
private DbConnection()
{
// ...
totalConnections++;
}
https://riptutorial.com/es/home 34
return new DbConnection();
}
else {
throw new NoDbConnections();
}
}
El método estático de fábrica es una variación del patrón de método de fábrica . Se utiliza para
crear objetos sin tener que llamar al constructor.
Ejemplo
Pizza.cs
private Pizza()
{
https://riptutorial.com/es/home 35
SizeDiameterCM = 25;
}
Programa.cs
class Program
{
static void Main(string[] args)
{
var pizzaNormal = Pizza.GetPizza();
var pizzaLarge = Pizza.GetLargePizza();
var pizzaSmall = Pizza.GetSmallPizza();
Salida
https://riptutorial.com/es/home 36
Capítulo 9: Método de plantilla
Examples
Implementación del método de plantilla en java.
Estructura:
Notas clave:
Ejemplo de código:
import java.util.List;
class GameRule{
}
class GameInfo{
String gameName;
List<String> players;
List<GameRule> rules;
}
https://riptutorial.com/es/home 37
protected GameInfo info;
public Game(GameInfo info){
this.info = info;
}
public abstract void createGame();
public abstract void makeMoves();
public abstract void applyRules();
}
class Ludo extends Game{
public Ludo(GameInfo info){
super(info);
}
public void createGame(){
// Use GameInfo and create Game
System.out.println("Creating Ludo game");
https://riptutorial.com/es/home 38
}
public void makeMoves(){
System.out.println("Make Ludo moves");
}
public void applyRules(){
System.out.println("Apply Ludo rules");
}
}
Explicación:
1. Game es una súper clase abstract , que define un método de plantilla: playGame()
3. Las playGame() como Chess, Ludo y Checkers no pueden cambiar el esqueleto de playGame() .
Pero pueden modificar el comportamiento de algunos pasos como
createGame();
makeMoves();
applyRules();
salida:
--------------------
Creating Chess game
Make Chess moves
Apply Chess rules
Close game:Chess
--------------------
Creating Ludo game
Make Ludo moves
Apply Ludo rules
Close game:Ludo
--------------------
Creating Checkers game
Make Checkers moves
Apply Checkers rules
Close game:Checkers
--------------------
https://riptutorial.com/es/home 39
plantilla
https://riptutorial.com/es/home 40
Capítulo 10: Monostato
Observaciones
Como nota al margen, algunas ventajas del patrón de Monostate sobre el Singleton :
Examples
El Patrón de Monostato
El patrón de Monostate se suele denominar azúcar sintáctico sobre el patrón de Singleton o como
un Singleton conceptual .
Evita todas las complicaciones de tener una sola instancia de una clase, pero todas las instancias
usan los mismos datos.
Esto se logra principalmente mediante el uso de miembros de datos static .
Una de las características más importantes es que es absolutamente transparente para los
usuarios, que desconocen por completo que están trabajando con un Monostate . Los usuarios
pueden crear tantas instancias de Monostate como deseen y cualquier instancia es tan buena
como otra para acceder a los datos.
La clase Monostate generalmente viene con una clase complementaria que se usa para actualizar
la configuración si es necesario.
struct Settings {
Settings() {
if(!initialized) {
initialized = true;
// load from file or db or whatever
// otherwise, use the SettingsEditor to initialize settings
Settings::width_ = 42;
Settings::height_ = 128;
}
}
private:
friend class SettingsEditor;
https://riptutorial.com/es/home 41
static bool initialized;
static std::size_t width_;
static std::size_t height_;
};
struct SettingsEditor {
void width(std::size_t value) noexcept { Settings::width_ = value; }
void height(std::size_t value) noexcept { Settings::height_ = value; }
};
static {
width = 42;
height = 128;
}
}
En contraste con el Singleton , el Monostate es adecuado para ser heredado para extender sus
funcionalidades, siempre que los métodos de los miembros no sean static .
Sigue un ejemplo mínimo en C ++:
struct Settings {
virtual std::size_t width() const noexcept { return width_; }
virtual std::size_t height() const noexcept { return height_; }
private:
static std::size_t width_;
static std::size_t height_;
};
https://riptutorial.com/es/home 42
std::size_t Settings::width_{0};
std::size_t Settings::height_{0};
https://riptutorial.com/es/home 43
Capítulo 11: Multiton
Observaciones
Multitonitis
Igual que Singleton , Multiton puede considerarse una mala práctica. Sin embargo, hay ocasiones
en las que puede usarlo sabiamente (por ejemplo, si está creando un sistema como ORM / ODM
para conservar múltiples objetos).
Examples
Pool of Singletons (ejemplo PHP)
Este es un ejemplo de cómo se puede crear la clase de grupo abstracta Multiton abstracta:
/**
* Get class name of lately binded class
*
* @return string
*/
final protected static function getClassName()
{
return get_called_class();
}
/**
* Instantiates a calling class object
*
* @return static
*/
public static function getInstance()
{
$className = static::getClassName();
if( !isset(self::$instances[$className]) ) {
self::$instances[$className] = new $className;
}
return self::$instances[$className];
}
https://riptutorial.com/es/home 44
/**
* Deletes a calling class object
*
* @return void
*/
public static function deleteInstance()
{
$className = static::getClassName();
if( isset(self::$instances[$className]) )
unset(self::$instances[$className]);
}
/*-------------------------------------------------------------------------
| Seal methods that can instantiate the class
|------------------------------------------------------------------------*/
Este patrón se puede usar para contener grupos de Singletons registrados, cada uno distinguido
por un ID único:
/**
* @param string $id
*/
final protected function __construct($id) {}
/**
* Get class name of lately binded class
*
* @return string
*/
final protected static function getClassName()
{
return get_called_class();
}
/**
* Instantiates a calling class object
*
* @return static
https://riptutorial.com/es/home 45
*/
public static function getInstance($id)
{
$className = static::getClassName();
if( !isset(self::$instances[$className]) ) {
self::$instances[$className] = [$id => new $className($id)];
} else {
if( !isset(self::$instances[$className][$id]) ) {
self::$instances[$className][$id] = new $className($id);
}
}
return self::$instances[$className][$id];
}
/**
* Deletes a calling class object
*
* @return void
*/
public static function unsetInstance($id)
{
$className = static::getClassName();
if( isset(self::$instances[$className]) ) {
if( isset(self::$instances[$className][$id]) ) {
unset(self::$instances[$className][$id]);
}
if( empty(self::$instances[$className]) ) {
unset(self::$instances[$className]);
}
}
}
/*-------------------------------------------------------------------------
| Seal methods that can instantiate the class
|------------------------------------------------------------------------*/
Esta es una forma simplificada de patrón que se puede usar para que ORM almacene varias
entidades de un tipo dado.
https://riptutorial.com/es/home 46
Capítulo 12: MVC, MVVM, MVP
Observaciones
Se puede argumentar que MVC y los patrones relacionados son en realidad patrones de
arquitectura de software en lugar de patrones de diseño de software.
Examples
Controlador de vista de modelo (MVC)
1. ¿Qué es MVC?
El patrón del controlador de vista de modelo (MVC) es un patrón de diseño más comúnmente
utilizado para crear interfaces de usuario. La principal ventaja de MVC es que separa:
El caso de uso principal de MVC está en la programación de la interfaz gráfica de usuario (GUI).
El componente Ver escucha el componente del Modelo en busca de cambios. El modelo actúa
como una emisora; cuando hay un modo de cambio en el Modelo, transmite sus cambios a la
Vista y al Controlador. El controlador es utilizado por la vista para modificar el componente del
modelo.
3. Implementación
Considere la siguiente implementación de MVC, donde tenemos una clase de modelo llamada
Animals , una clase de vista llamada DisplayAnimals y una clase de controlador llamada
AnimalController . El siguiente ejemplo es una versión modificada del tutorial en MVC de Design
Patterns - MVC Pattern .
/* Model class */
public class Animals {
private String name;
private String gender;
https://riptutorial.com/es/home 47
public void setName(String name) {
this.name = name;
}
/* View class */
public class DisplayAnimals {
public void printAnimals(String tag, String gender) {
System.out.println("My Tag name for Animal:" + tag);
System.out.println("My gender: " + gender);
}
}
/* Controller class */
public class AnimalController {
private Animal model;
private DisplayAnimals view;
4. Fuentes utilizadas:
https://riptutorial.com/es/home 48
1. ¿Qué es MVVM?
El patrón Model View ViewModel (MVVM) es un patrón de diseño más comúnmente utilizado para
crear interfaces de usuario. Se deriva del popular patrón "Model View Controller" (MVC). La
principal ventaja de MVVM es que separa:
En Windows Presentation Foundation (WPF), por ejemplo, la vista se diseña utilizando el lenguaje
de marcado de marco XAML. Los archivos XAML están vinculados a ViewModels mediante el
enlace de datos. De esta manera, la vista solo es responsable de la presentación y el modelo de
vista solo es responsable de administrar el estado de la aplicación trabajando en los datos del
modelo.
3. Implementación
Considere la siguiente implementación de MVVM usando C # .Net y WPF. Tenemos una clase de
modelo llamada Animales, una clase de vista implementada en Xaml y un modelo de vista
llamado AnimalViewModel. El siguiente ejemplo es una versión modificada del tutorial en MVC de
Design Patterns - MVC Pattern .
Mira cómo el modelo no sabe nada, el ViewModel solo sabe sobre el modelo y la vista solo
conoce el ViewModel.
El evento OnNotifyPropertyChanged permite actualizar tanto el modelo como la vista para que
cuando ingrese algo en el cuadro de texto en la vista, se actualice el modelo. Y si algo actualiza el
modelo, la vista se actualiza.
/*Model class*/
public class Animal
{
public string Name { get; set; }
/*ViewModel class*/
public class AnimalViewModel : INotifyPropertyChanged
{
https://riptutorial.com/es/home 49
private Animal _model;
public AnimalViewModel()
{
_model = new Animal {Name = "Cat", Gender = "Male"};
}
<Window.DataContext>
<viewModel:AnimalViewModel/>
</Window.DataContext>
<StackPanel>
<TextBox Text="{Binding AnimalName}" Width="120" />
<TextBox Text="{Binding AnimalGender}" Width="120" />
</StackPanel>
</Window>
4. Fuentes utilizadas:
https://riptutorial.com/es/home 50
Model – view – viewmodel
El patrón MVVM
https://riptutorial.com/es/home 51
Capítulo 13: Observador
Observaciones
¿Cuál es la intención?
¿Cuál es la estructura?
Examples
Observador / Java
El patrón de observador permite a los usuarios de una clase suscribirse a eventos que suceden
cuando esta clase procesa datos, etc. y ser notificado cuando ocurren estos eventos. En el
siguiente ejemplo, creamos una clase de procesamiento y una clase de observador a las que se
notificará mientras se procesa una frase, si encuentra palabras que tengan más de 5 letras.
La clase WordEvent es el evento que se enviará a las clases de observadores una vez que ocurran
ciertos eventos (en este caso, se encontraron palabras largas)
// An event class which contains the long word that was found
public class WordEvent {
https://riptutorial.com/es/home 52
private String word;
La clase PhraseProcessor es la clase que procesa la frase dada. Permite que los observadores se
registren utilizando el método addObserver . Una vez que se encuentran palabras largas, se
llamará a estos observadores utilizando una instancia de la clase WordEvent .
import java.util.ArrayList;
import java.util.List;
// register an observer
public void addObserver(LongWordsObserver observer) {
observers.add(observer);
}
// the main method - process a phrase and look for long words. If such are found,
// notify all the observers
public void process(String phrase) {
for (String word : phrase.split(" ")) {
if (word.length() > 5) {
informObservers(word);
}
}
}
}
import java.util.ArrayList;
import java.util.List;
https://riptutorial.com/es/home 53
// create the PhraseProcessor class
PhraseProcessor processor = new PhraseProcessor();
https://riptutorial.com/es/home 54
public Unsubscriber(IList<IObserver<Stock>> observers, IObserver<Stock> observer) {
_observers = observers;
_observer = observer;
}
Uso
...
var provider = new StockTrader();
var i1 = new Investor();
i1.Subscribe(provider);
var i2 = new Investor();
i2.Subscribe(provider);
provider.Trade(new Stock());
provider.Trade(new Stock());
provider.Trade(null);
provider.End();
...
https://riptutorial.com/es/home 55
Capítulo 14: Patrón compuesto
Examples
Maderero compuesto
El patrón compuesto es un patrón de diseño que permite tratar un grupo de objetos como una
instancia única de un objeto. Es uno de los patrones de diseño estructural de Gang of Four.
El siguiente ejemplo muestra cómo se puede utilizar Composite para iniciar sesión en múltiples
lugares mediante una invocación única de registro. Este enfoque se adhiere a los principios de
SOLID porque le permite agregar un nuevo mecanismo de registro sin violar el principio de
responsabilidad única (cada registrador tiene solo una responsabilidad) o el principio de apertura /
cierre (puede agregar un nuevo registrador que se registrará en un nuevo lugar agregando una
nueva implementación y no modificando los existentes).
https://riptutorial.com/es/home 56
var compositeLogger = new CompositeLogger(new ConsoleLogger(), new FileLogger());
compositeLogger.Log("some message"); //this will be invoked both on ConsoleLogger and
FileLogger
Vale la pena mencionar que los registradores compuestos se pueden anidar (uno de los
parámetros del constructor de registradores compuestos puede ser otro registrador compuesto)
creando una estructura similar a un árbol.
https://riptutorial.com/es/home 57
Capítulo 15: Patrón compuesto
Introducción
Compuesto permite a los clientes tratar objetos individuales y composiciones de objetos de
manera uniforme. Por ejemplo, considere un programa que manipula un sistema de archivos. Los
archivos son objetos simples y las carpetas son composiciones de archivos y carpetas. Sin
embargo, por ejemplo, ambos tienen funciones de tamaño, nombre, etc. Sería más fácil y más
conveniente tratar los objetos de archivos y carpetas de manera uniforme definiendo una Interfaz
de recursos del sistema de archivos
Observaciones
El patrón compuesto se aplica cuando hay una jerarquía parcial de objetos y un cliente necesita
tratar los objetos de manera uniforme, independientemente del hecho de que un objeto pueda ser
una hoja (objeto simple) o una rama (objeto compuesto).
Examples
pseudocódigo para un administrador de archivos tontos
/*
* Component is an interface
* which all elements (files,
* folders, links ...) will implement
*/
class Component
{
public:
virtual int getSize() const = 0;
};
/*
* File class represents a file
* in file system.
*/
class File : public Component
{
public:
virtual int getSize() const {
// return file size
}
};
/*
* Folder is a component and
* also may contain files and
* another folders. Folder is a
* composition of components
*/
class Folder : public Component
https://riptutorial.com/es/home 58
{
public:
void addComponent(Component* aComponent) {
// mList append aComponent;
}
void removeComponent(Component* aComponent) {
// remove aComponent from mList
}
virtual int getSize() const {
int size = 0;
foreach(component : mList) {
size += component->getSize();
}
return size;
}
private:
list<Component*> mList;
};
https://riptutorial.com/es/home 59
Capítulo 16: Patrón de comando
Examples
Ejemplo de patrón de comando en Java
definición de wikipedia :
1. Command declara una interfaz para los comandos abstractos como execute()
2. Receiver sabe cómo ejecutar un comando en particular
3. Invoker posee ConcreteCommand , que debe ser ejecutado.
4. Client crea ConcreteCommand y asigna un Receiver
5. ConcreteCommand define el enlace entre Command y Receiver
De esta manera, el patrón de comando desacopla al remitente (cliente) del receptor a través del
invocador . El Invoker tiene un conocimiento completo de qué Comando se ejecutará y el
Comando sabe qué Receptor se debe invocar para ejecutar una operación en particular.
Fragmento de código:
interface Command {
void execute();
}
class Receiver {
public void switchOn(){
System.out.println("Switch on from:"+this.getClass().getSimpleName());
}
https://riptutorial.com/es/home 60
}
class OnCommand implements Command{
private Receiver receiver;
salida:
Switch on from:TV
Switch on from:DVDPlayer
Explicación:
En este ejemplo,
https://riptutorial.com/es/home 61
1. La interfaz de comandos define el método execute() .
2. OnCommand es ConcreteCommand , que implementa el método execute() .
3. El receptor es la clase base.
4. TV y DVDPlayer son dos tipos de receptores , que se pasan a ConcreteCommand como
OnCommand.
5. Invoker contiene el comando . Es la clave para separar el remitente del receptor .
6. El invocador recibe OnCommand -> que llama a Receiver (TV) para ejecutar este
comando.
https://riptutorial.com/es/home 62
Capítulo 17: Patrón de constructor
Observaciones
Separa la construcción de un objeto complejo de su representación para que el mismo proceso de
construcción pueda crear diferentes representaciones.
Examples
Patrón del constructor / C # / Interfaz fluida
public EmailBuilder()
{
_email = new Email();
}
https://riptutorial.com/es/home 63
public Email Build()
{
return _email;
}
}
Ejemplo de uso:
El patrón Builder le permite crear una instancia de una clase con muchas variables opcionales de
una manera fácil de leer.
Todo esto está muy bien si todos los parámetros son necesarios. ¿Qué pasa si hay muchas más
variables y / o algunas de ellas son opcionales? No desea crear un gran número de constructores
con cada combinación posible de parámetros obligatorios y opcionales porque resulta difícil
mantenerlos y comprenderlos los desarrolladores. Es posible que tampoco desee tener una larga
lista de parámetros en los que el usuario deba ingresar muchos de ellos como nulos.
El patrón Builder crea una clase interna llamada Builder que se utiliza para instanciar solo las
variables opcionales deseadas. Esto se realiza a través de métodos para cada variable opcional
que toman el tipo de variable como un parámetro y devuelven un objeto Builder para que los
métodos se puedan encadenar entre sí. Todas las variables necesarias se colocan en el
constructor del generador para que no se puedan omitir.
El Generador también incluye un método llamado build() que devuelve el objeto en el que se
https://riptutorial.com/es/home 64
encuentra y debe llamarse al final de la cadena de llamadas de métodos al generar el objeto.
Siguiendo con el ejemplo anterior, este código usa el patrón de Generador para la clase de
Computadora.
https://riptutorial.com/es/home 65
public Computer build() {
return new Computer(this);
}
}
}
Este ejemplo muestra cómo el patrón de constructor puede permitir una gran flexibilidad en la
forma en que se crea una clase con bastante poco esfuerzo. El objeto Computadora se puede
implementar en función de la configuración deseada de los que llaman de una manera fácil de
leer con poco esfuerzo.
Intención:
El patrón de generador es útil cuando tiene pocos atributos obligatorios y muchos atributos
opcionales para construir un objeto. Para crear un objeto con diferentes atributos obligatorios y
opcionales, debe proporcionar un constructor complejo para crear el objeto. El patrón del
generador proporciona un proceso paso a paso simple para construir un objeto complejo.
Los diferentes usuarios de FaceBook tienen atributos diferentes, que consisten en atributos
obligatorios como el nombre de usuario y atributos opcionales como UserBasicInfo y ContactInfo.
Algunos usuarios simplemente proporcionan información básica. Algunos usuarios proporcionan
información detallada que incluye información de contacto. En ausencia del patrón Builder, debe
proporcionar un constructor con todos los parámetros obligatorios y opcionales. Pero el patrón
Builder simplifica el proceso de construcción al proporcionar un proceso paso a paso simple para
construir el objeto complejo.
https://riptutorial.com/es/home 66
Consejos:
Fragmento de código:
import java.util.*;
class UserBasicInfo{
String nickName;
String birthDate;
String gender;
sb.append("Name:DOB:Gender:").append(nickName).append(":").append(birthDate).append(":").
append(gender);
return sb.toString();
}
}
class ContactInfo{
String eMail;
String mobileHome;
String mobileWork;
sb.append("email:mobile(H):mobile(W):").append(eMail).append(":").append(mobileHome).append(":").append
return sb.toString();
}
}
class FaceBookUser {
String userName;
UserBasicInfo userInfo;
ContactInfo contactInfo;
https://riptutorial.com/es/home 67
this.userInfo = info;
}
public void setContactInfo(ContactInfo info){
this.contactInfo = info;
}
public String getUserName(){
return userName;
}
public UserBasicInfo getUserBasicInfo(){
return userInfo;
}
public ContactInfo getContactInfo(){
return contactInfo;
}
sb.append("|User|").append(userName).append("|UserInfo|").append(userInfo).append("|ContactInfo|").appe
return sb.toString();
}
https://riptutorial.com/es/home 68
}
salida:
Explicación:
1. FaceBookUser es un objeto complejo con los siguientes atributos que utilizan composición:
String userName;
UserBasicInfo userInfo;
ContactInfo contactInfo;
5. Este ejemplo ilustra tres diferentes FaceBookUsers con diferentes atributos, construidos
desde Builder.
En los patrones de creación, primero comenzaremos con patrones simples como FactoryMethod y
FactoryMethod hacia patrones más flexibles y complejos como AbstractFactory y Builder .
Java / Lombok
import lombok.Builder;
@Builder
public class Email {
https://riptutorial.com/es/home 69
Ejemplo de uso:
Email.builder().to("[email protected]")
.from("[email protected]")
.subject("Email subject")
.body("Email content")
.build();
public Person(String salutation, String firstName, String middleName, String lastName, String
suffix, Address address, boolean isFemale, boolean isEmployed, boolean isHomewOwner) {
this.salutation = salutation;
this.firstName = firstName;
this.middleName = middleName;
this.lastName = lastName;
this.suffix = suffix;
this.address = address;
this.isFemale = isFemale;
this.isEmployed = isEmployed;
this.isHomewOwner = isHomewOwner;
}
}
Vieja forma
https://riptutorial.com/es/home 70
public PersonBuilder withMiddleName(String middleName) {
this.middleName = middleName;
return this;
}
Manera avanzada:
https://riptutorial.com/es/home 71
public Person createPerson() {
return new Person(salutation, firstName, middleName,
lastName, suffix, address, isFemale,
isEmployed, isHomewOwner);
}
Uso:
Consulte: https://medium.com/beingprofessional/think-functional-advanced-builder-pattern-using-
lambda-284714b85ed5#.d9sryx3g9
https://riptutorial.com/es/home 72
Capítulo 18: Patrón de diseño del objeto de
acceso a datos (DAO)
Examples
Patrón de diseño de objetos de acceso a datos J2EE con Java
El patrón de diseño del objeto de acceso a datos (DAO) es un patrón de diseño estándar de
J2EE.
En este patrón de diseño, se accede a los datos a través de clases que contienen métodos para
acceder a datos desde bases de datos u otras fuentes, que se denominan objetos de acceso a
datos . La práctica estándar asume que hay clases POJO. DAO se puede combinar con otros
patrones de diseño para acceder a los datos, como con MVC (controlador de vista de modelo),
patrones de comando, etc.
El siguiente es un ejemplo de patrón de diseño DAO. Tiene una clase de Empleado , un DAO
para Empleado llamado EmployeeDAO y una clase de ApplicationView para demostrar los
ejemplos.
Empleado.java
public Employee(){
Empleado
https://riptutorial.com/es/home 73
public EmployeeDAO(List<Employee> employeeList){
this.employeeList = employeeList;
}
return employee;
}
ApplicationView.java
https://riptutorial.com/es/home 74
}
Por lo tanto, tenemos un ejemplo en el que vemos cómo usar el patrón de diseño de Data Access
Object.
https://riptutorial.com/es/home 75
Capítulo 19: Patrón de estrategia
Examples
Ocultar los detalles de la implementación de la estrategia.
Una guía muy común en el diseño orientado a objetos es "lo menos posible pero lo necesario".
Esto también se aplica al patrón de estrategia: por lo general, es recomendable ocultar los
detalles de la implementación, por ejemplo, qué clases implementan las estrategias.
Para estrategias simples que no dependen de parámetros externos, el enfoque más común es
hacer que la clase implementadora sea privada (clases anidadas) o paquete-privada y exponga
una instancia a través de un campo estático de una clase pública:
// Note that this field has the generic type Comparator<Animal>, *not*
// Animal.AgeComparator!
public static final Comparator<Animal> AGE_COMPARATOR = new AgeComparator();
Animal(int age) {
this.age = age;
}
Collections.sort(
myList,
Animal.AGE_COMPARATOR
);
El campo público Animal.AGE_COMPARATOR define una estrategia que luego se puede usar en
métodos como Collections.sort , pero no requiere que el usuario sepa nada sobre su
implementación, ni siquiera la clase implementadora.
https://riptutorial.com/es/home 76
Si lo prefieres, puedes usar una clase anónima:
// other members...
}
Si la estrategia es un poco más compleja y requiere parámetros, es muy común usar métodos de
fábrica estáticos como Collections.reverseOrder(Comparator<T>) . El tipo de retorno del método no
debe exponer ningún detalle de implementación, por ejemplo, reverseOrder() se implementa como
Estrategia:
import java.util.*;
https://riptutorial.com/es/home 77
return 0;
}
}
/* Concrete implementation of base Strategy */
class QuarterDiscountStrategy implements OfferStrategy{
public String getName(){
return this.getClass().getName();
}
public double getDiscountPercentage(){
return 0.25;
}
}
/* Context is optional. But if it is present, it acts as single point of contact
for client.
}
}
public class StrategyDemo{
public static void main(String args[]){
StrategyContext context = new StrategyContext(100);
System.out.println("Enter month number between 1 and 12");
int month = Integer.parseInt(args[0]);
System.out.println("Month ="+month);
https://riptutorial.com/es/home 78
OfferStrategy strategy = context.getStrategy(month);
context.applyStrategy(strategy);
}
salida:
Declaración de problema: Ofrezca un descuento del 25% en el precio del artículo para los meses
de julio a diciembre. No ofrezca ningún descuento por los meses de enero-junio.
El ejemplo anterior muestra el uso del patrón de Strategy con Context . Context se puede utilizar
como un único punto de contacto para el Client .
Como se muestra en la columna de salida, obtendrá un descuento dependiendo del mes que
haya ingresado
1. Use este patrón cuando tenga una familia de algoritmos intercambiables y tenga que
cambiar el algoritmo en tiempo de ejecución.
El siguiente es un ejemplo simple de usar el patrón de estrategia sin una clase de contexto.
Existen dos estrategias de implementación que implementan la interfaz y resuelven el mismo
problema de diferentes maneras. Los usuarios de la clase de traducción en inglés pueden llamar
al método de traducción y elegir qué estrategia les gustaría usar para la traducción, especificando
la estrategia deseada.
https://riptutorial.com/es/home 79
@Override
public String translate(String phrase) {
return phrase + ", bro";
}
}
@Override
public String translate(String phrase) {
return phrase + ", mate";
}
}
// example usage
public static void main(String[] args) {
El propósito de este ejemplo es mostrar cómo podemos realizar el patrón de estrategia utilizando
las interfaces funcionales de Java 8. Comenzaremos con un simple uso de códigos de casos en
Java clásico, y luego lo recodificaremos en la forma de Java 8.
El problema de ejemplo que usamos es una familia de algoritmos (estrategias) que describen
diferentes formas de comunicación a distancia.
https://riptutorial.com/es/home 80
Luego podemos implementar una serie de algoritmos, de la siguiente manera:
// via phone
communicationService.setCommuncationMeans(communicateViaPhone);
communicationService.communicate("1234567");
// via email
communicationService.setCommuncationMeans(communicateViaEmail);
communicationService.communicate("[email protected]");
https://riptutorial.com/es/home 81
Usando interfaces funcionales de Java 8
El contrato de las diferentes implementaciones de algoritmos no necesita una interfaz dedicada.
En su lugar, podemos describirlo utilizando la interfaz java.util.function.Function<T, R> .
Los diferentes algoritmos que componen the family of algorithms se pueden expresar como
expresiones lambda. Esto reemplaza las clases de estrategia y sus instancias.
// via phone
communicationService.setCommuncationMeans(communicateViaPhone);
communicationService.communicate("1234567");
// via email
communicationService.setCommuncationMeans(communicateViaEmail);
communicationService.communicate("[email protected]");
O incluso:
communicationService.setCommuncationMeans(
destination -> "communicating " + destination + " via Smoke signals.." );
CommunicationService.communicate("anyone");
Estrategia (PHP)
Ejemplo de www.phptherightway.com
<?php
https://riptutorial.com/es/home 82
interface OutputInterface
{
public function load();
}
https://riptutorial.com/es/home 83
Capítulo 20: Patrón de iterador
Examples
El patrón iterador
Las colecciones son una de las estructuras de datos más utilizadas en ingeniería de software.
Una Colección es solo un grupo de objetos. Una colección puede ser una Lista, una matriz, un
mapa, un árbol o cualquier cosa. Por lo tanto, una colección debe proporcionar alguna forma de
acceder a sus elementos sin exponer su estructura interna. Deberíamos poder recorrerlo de la
misma manera, independientemente del tipo de colección que sea.
La idea del patrón de iterador es asumir la responsabilidad de acceder al objeto de una colección
y colocarlo en un objeto iterador. El objeto iterador a cambio mantendrá el orden de iteración,
mantendrá un seguimiento del elemento actual y deberá tener una forma de obtener el siguiente
elemento.
https://riptutorial.com/es/home 84
}
@Override
public boolean hasNext() {
return index < fruits.length;
}
@Override
public Object next() {
if(this.hasNext()) {
return names[index++];
}
return null;
}
}
}
https://riptutorial.com/es/home 85
Capítulo 21: Patrón de objeto nulo
Observaciones
El objeto nulo es un objeto sin valor referenciado o con un comportamiento neutral definido. Su
propósito es eliminar la necesidad de puntero nulo / verificación de referencia.
Examples
Patrón de objeto nulo (C ++)
class ILogger {
virtual ~ILogger() = default;
virtual Log(const std::string&) = 0;
};
En lugar de
void doJobWithoutLogging()
{
doJob(nullptr);
}
https://riptutorial.com/es/home 86
// ...
logger.Log("[doJob]:Step 2");
// ...
logger.Log("[doJob]:End");
}
void doJobWithoutLogging()
{
NullLogger logger;
doJob(logger);
}
En lugar de uso:
Debido a que los objetos nulos no tienen un estado, tiene sentido utilizar un singleton de
enumeración para ellos, por lo que, dado un objeto nulo implementado así:
@Override
public void log(String message) {
// Do nothing
}
}
https://riptutorial.com/es/home 87
logger.log("[doJob]:Step 1");
// ...
logger.log("[doJob]:Step 2");
// ...
logger.log("[doJob]:Step 3");
}
https://riptutorial.com/es/home 88
Capítulo 22: Patrón de puente
Examples
Implementación de patrón puente en java
The crux of Bridge pattern : dos jerarquías de clases ortogonales que usan composición (y no
herencia). La jerarquía de abstracción y la jerarquía de implementación pueden variar
independientemente. Implementación nunca se refiere a la abstracción. La abstracción contiene la
interfaz de implementación como miembro (a través de la composición). Esta composición reduce
un nivel más de jerarquía de herencia.
Permitir que diferentes vehículos tengan ambas versiones de sistema manual y automático.
Código de ejemplo:
/* Implementor interface*/
interface Gear{
https://riptutorial.com/es/home 89
void handleGear();
}
/* Concrete Implementor - 1 */
class ManualGear implements Gear{
public void handleGear(){
System.out.println("Manual gear");
}
}
/* Concrete Implementor - 2 */
class AutoGear implements Gear{
public void handleGear(){
System.out.println("Auto gear");
}
}
/* Abstraction (abstract class) */
abstract class Vehicle {
Gear gear;
public Vehicle(Gear gear){
this.gear = gear;
}
abstract void addGear();
}
/* RefinedAbstraction - 1*/
class Car extends Vehicle{
public Car(Gear gear){
super(gear);
// initialize various other Car components to make the car
}
public void addGear(){
System.out.print("Car handles ");
gear.handleGear();
}
}
/* RefinedAbstraction - 2 */
class Truck extends Vehicle{
public Truck(Gear gear){
super(gear);
// initialize various other Truck components to make the car
}
public void addGear(){
System.out.print("Truck handles " );
gear.handleGear();
}
}
/* Client program */
public class BridgeDemo {
public static void main(String args[]){
Gear gear = new ManualGear();
Vehicle vehicle = new Car(gear);
vehicle.addGear();
https://riptutorial.com/es/home 90
vehicle = new Truck(gear);
vehicle.addGear();
}
}
salida:
Explicación:
https://riptutorial.com/es/home 91
Capítulo 23: Patrón de repositorio
Observaciones
Acerca de la implementación de IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter)
: La idea de esto es usar Expresiones como i => x.id == 17 para escribir solicitudes genéricas. Es
una forma de consultar datos sin utilizar el lenguaje de consulta específico de su tecnología. La
implementación es bastante extensa, por lo tanto, es posible que desee considerar otras
alternativas, como métodos específicos en sus repositorios implementados: un CompanyRepository
imaginario podría proporcionar el método GetByName(string name) .
Examples
Repositorios de solo lectura (C #)
Los repositorios de solo lectura se pueden usar para crear repositorios a los que no se les permite
manipular datos.
Las interfaces
public interface IReadOnlyRepository<TEntity, TKey> : IRepository
{
IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter);
https://riptutorial.com/es/home 92
public abstract class ElasticReadRepository<TModel> : IReadOnlyRepository<TModel, string>
where TModel : class
{
public ElasticReadRepository()
{
Client = Connect();
}
Con esta implementación, ahora puede crear Repositorios específicos para los elementos que
desea almacenar o acceder. Cuando se utiliza la búsqueda elástica, es común que algunos
componentes solo lean los datos, por lo que se deben usar repositorios de solo lectura.
Interfaz de repositorio;
https://riptutorial.com/es/home 93
void Insert(T entity);
void Insert(ICollection<T> entities);
void Delete(T entity);
void Delete(ICollection<T> entity);
IQueryable<T> SearchFor(Expression<Func<T, bool>> predicate);
IQueryable<T> GetAll();
T GetById(int id);
}
Repositorio genérico;
https://riptutorial.com/es/home 94
var hotelRepo = new Repository<Hotel>(db);
https://riptutorial.com/es/home 95
Capítulo 24: Patrón de visitante
Examples
Ejemplo de patrón de visitante en C ++
En lugar de
struct IShape
{
virtual ~IShape() = default;
struct Point {
double x;
double y;
};
https://riptutorial.com/es/home 96
Point center;
double radius;
};
Point topLeft;
double sideLength;
};
double area = 0;
};
Y úsalo:
ShapePrinter shapePrinter;
ShapeAreaComputer shapeAreaComputer;
ShapePerimeterComputer shapePerimeterComputer;
https://riptutorial.com/es/home 97
shape->accept(shapePrinter);
std::cout << " has an area of ";
Rendimiento esperado:
Manifestación
Explicación :
Pros :
• Puede agregar una nueva funcionalidad ( SerializeAsXml , ...) a la clase IShape simplemente
agregando un nuevo visitante.
Contras :
• Agregar una nueva forma concreta ( Triangle , ...) requiere modificar todos los visitantes.
La alternativa de poner todas las funcionalidades como métodos virtual en IShape tiene ventajas
y desventajas opuestas: agregar una nueva funcionalidad requiere modificar todas las formas
existentes, pero agregar una nueva forma no afecta las clases existentes.
Este patrón es especialmente útil cuando desea centralizar una operación particular en un objeto
sin extender el objeto o sin modificar el objeto.
https://riptutorial.com/es/home 98
Diagrama UML de wikipedia:
Fragmento de código:
import java.util.HashMap;
interface Visitable{
void accept(Visitor visitor);
}
interface Visitor{
void logGameStatistics(Chess chess);
void logGameStatistics(Checkers checkers);
void logGameStatistics(Ludo ludo);
}
class GameVisitor implements Visitor{
public void logGameStatistics(Chess chess){
System.out.println("Logging Chess statistics: Game Completion duration, number of
moves etc..");
}
public void logGameStatistics(Checkers checkers){
System.out.println("Logging Checkers statistics: Game Completion duration, remaining
coins of loser");
}
public void logGameStatistics(Ludo ludo){
System.out.println("Logging Ludo statistics: Game Completion duration, remaining coins
of loser");
}
}
}
public void getNextMove(){};
public void makeNextMove(){}
public abstract String getName();
}
class Chess extends Game implements Visitable{
public String getName(){
return Chess.class.getName();
}
https://riptutorial.com/es/home 99
public void accept(Visitor visitor){
visitor.logGameStatistics(this);
}
}
class Checkers extends Game implements Visitable{
public String getName(){
return Checkers.class.getName();
}
public void accept(Visitor visitor){
visitor.logGameStatistics(this);
}
}
class Ludo extends Game implements Visitable{
public String getName(){
return Ludo.class.getName();
}
public void accept(Visitor visitor){
visitor.logGameStatistics(this);
}
}
Explicación:
1. Visitable ( Element ) es una interfaz y este método de interfaz debe agregarse a un conjunto
de clases.
2. Visitor es una interfaz, que contiene métodos para realizar una operación en elementos
Visitable .
3. GameVisitor es una clase que implementa una interfaz de Visitor ( ConcreteVisitor ).
4. Cada elemento Visitable acepta Visitor e invoca un método relevante de interfaz de Visitor
.
5. Puedes tratar el Game como Element y los juegos concretos como Chess,Checkers and Ludo
como Element ConcreteElements .
En el ejemplo anterior, Chess, Checkers and Ludo son tres juegos diferentes (y clases Visitable ).
En un buen día, me encontré con un escenario para registrar estadísticas de cada juego. Por lo
tanto, sin modificar la clase individual para implementar la funcionalidad de estadísticas, puede
centralizar esa responsabilidad en la clase GameVisitor , que hace el truco por usted sin modificar
la estructura de cada juego.
salida:
https://riptutorial.com/es/home 100
Casos de uso / Aplicabilidad:
Referencias adicionales:
oodesign
sourcemaking
Ejemplo de visitante en C ++
https://riptutorial.com/es/home 101
class VehicleVisitor
{
public:
// The visitor interface implements one method for each class in the
// hierarchy. When implementing new functionality you just create the
// functionality required for each type in the appropriate method.
Un ejemplo de uso:
int main()
{
MoveVehicleVisitor moveToDenver("Denver");
Vehicle& object = getObjectToMove();
object.accept(moveToDenver);
}
class GraphVisitor;
class Graph
{
public:
class Node
{
using Link = std::set<Node>::iterator;
std::set<Link> linkTo;
public:
void accept(GraphVisitor& visitor);
};
private:
std::set<Node> nodes;
https://riptutorial.com/es/home 102
};
class GraphVisitor
{
std::set<Graph::Node*> visited;
public:
void visit(Graph& graph)
{
visited.clear();
doVisit(graph);
}
bool visit(Graph::Node& node)
{
if (visited.find(&node) != visited.end()) {
return false;
}
visited.insert(&node);
doVisit(node);
return true;
}
private:
virtual void doVisit(Graph& graph) = 0;
virtual void doVisit(Graph::Node& node) = 0;
};
https://riptutorial.com/es/home 103
Capítulo 25: Patrón decorador
Introducción
El patrón Decorator permite que un usuario agregue una nueva funcionalidad a un objeto
existente sin alterar su estructura. Este tipo de patrón de diseño se encuentra bajo un patrón
estructural ya que este patrón actúa como un envoltorio para la clase existente.
Este patrón crea una clase decoradora que envuelve la clase original y proporciona funcionalidad
adicional manteniendo intacta la firma de los métodos de clase.
Parámetros
Parámetro Descripción
Examples
VendingMachineDecorator
https://riptutorial.com/es/home 104
1. Interfaz de componentes: define una interfaz para ejecutar operaciones particulares
2. ConcreteComponent: implementa las operaciones definidas en la interfaz de componentes
3. Decorador (abstracto): es una clase abstracta, que amplía la interfaz del componente.
Contiene interfaz de componentes. En ausencia de esta clase, necesita muchas subclases
de ConcreteDecorators para diferentes combinaciones. La composición del componente
reduce las subclases innecesarias.
4. ConcreteDecorator: Posee la implementación de Abstract Decorator.
EDITAR: Cambié el ejemplo para reflejar el escenario del mundo real de calcular el precio de la
bebida agregando uno o más sabores como el azúcar, el limón, etc. (los sabores son
decoradores)
}
public Beverage(String name){
this.name = name;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
protected void setPrice(int price){
https://riptutorial.com/es/home 105
this.price = price;
}
protected int getPrice(){
return price;
}
protected abstract void decorateBeverage();
}
class Tea extends Beverage{
public Tea(String name){
super(name);
setPrice(10);
}
public void decorateBeverage(){
System.out.println("Cost of:"+ name +":"+ price);
// You can add some more functionality
}
}
class Coffee extends Beverage{
public Coffee(String name){
super(name);
setPrice(15);
}
public void decorateBeverage(){
System.out.println("Cost of:"+ name +":"+ price);
// You can add some more functionality
}
}
abstract class BeverageDecorator extends Beverage {
protected Beverage beverage;
public BeverageDecorator(Beverage beverage){
this.beverage = beverage;
setName(beverage.getName()+"+"+getDecoratedName());
setPrice(beverage.getPrice()+getIncrementPrice());
}
public void decorateBeverage(){
beverage.decorateBeverage();
System.out.println("Cost of:"+getName()+":"+getPrice());
}
public abstract int getIncrementPrice();
public abstract String getDecoratedName();
}
class SugarDecorator extends BeverageDecorator{
public SugarDecorator(Beverage beverage){
super(beverage);
}
public void decorateBeverage(){
super.decorateBeverage();
decorateSugar();
}
public void decorateSugar(){
System.out.println("Added Sugar to:"+beverage.getName());
}
public int getIncrementPrice(){
return 5;
}
public String getDecoratedName(){
return "Sugar";
}
}
class LemonDecorator extends BeverageDecorator{
https://riptutorial.com/es/home 106
public LemonDecorator(Beverage beverage){
super(beverage);
}
public void decorateBeverage(){
super.decorateBeverage();
decorateLemon();
}
public void decorateLemon(){
System.out.println("Added Lemon to:"+beverage.getName());
}
public int getIncrementPrice(){
return 3;
}
public String getDecoratedName(){
return "Lemon";
}
}
salida:
En el ejemplo anterior:
Costo del té = 10, Limón = 3 y Azúcar = 5. Si haces Azúcar + Limón + Té, cuesta 18.
Costo del café = 15, Limón = 3 y Azúcar = 5. Si haces Azúcar + Limón + Café, cuesta 23
Al utilizar el mismo Decorador para ambas bebidas (té y café), se ha reducido el número de
subclases. En ausencia del patrón de Decorator, deberías tener diferentes subclases para
diferentes combinaciones.
SugarLemonTea
https://riptutorial.com/es/home 107
SugarTea
LemonTea
SugarLemonCapaccuino
SugarCapaccuino
LemonCapaccuino
etc.
4. Decorator está diseñado para permitirle agregar responsabilidades a los objetos sin crear
subclases. El enfoque del compuesto no es el embellecimiento sino la representación.
Decorador de caching
https://riptutorial.com/es/home 108
{
public Product GetProduct(int id)
{
//return Product retrieved from DB
}
}
return product;
}
Uso:
https://riptutorial.com/es/home 109
Capítulo 26: Patrón mediador
Examples
Ejemplo de patrón mediador en java
El patrón de mediador define un objeto (mediador) que encapsula cómo interactúa un conjunto de
objetos. Permite la comunicación de muchos a muchos.
Diagrama UML:
Componentes clave:
Colleague : es una clase abstracta, que define los eventos que deben comunicarse entre colegas.
Una red de malla es una topología de red en la que cada nodo transmite datos para la red. Todos
los nodos de malla cooperan en la distribución de datos en la red.
Si se agrega una computadora nueva o si se quita la computadora existente, todas las otras
computadoras en esa red deben conocer estos dos eventos.
Fragmento de código:
https://riptutorial.com/es/home 110
import java.util.List;
import java.util.ArrayList;
public NetworkMediator(){
https://riptutorial.com/es/home 111
}
}
public void unregister(Colleague colleague){
colleagues.remove(colleague);
for (Colleague other : colleagues){
other.receiveUnRegisterNotification(colleague);
}
}
}
salida:
Explicación:
1. Eagle se agrega a la red en primer lugar a través del evento de registro. No hay
notificaciones a ningún otro compañero ya que Eagle es el primero.
2. Cuando se agrega Ostrich a la red, se notifica a Eagle : la línea 1 de la salida se procesa
ahora.
3. Cuando se agrega Penguin a la red, tanto Eagle como Ostrich han sido notificados: la línea 2
y la línea 3 de la salida se procesan ahora.
4. Cuando Eagle abandonó la red a través del evento de desregistro, se notificó a Ostrich y
Penguin . La línea 4 y la línea 5 de salida se representan ahora.
https://riptutorial.com/es/home 112
Capítulo 27: Patrón prototipo
Introducción
El patrón de prototipo es un patrón de creación que crea nuevos objetos mediante la clonación de
un objeto prototipo existente. El patrón prototipo acelera la creación de instancias de clases
cuando la copia de objetos es más rápida.
Observaciones
El patrón prototipo es un patrón de diseño creativo. Se utiliza cuando el tipo de objetos a crear
está determinado por una instancia prototípica, que se "clona" para producir nuevos objetos.
Este patrón se usa cuando una clase necesita un "constructor polimórfico (copia)" .
Examples
Patrón de prototipo (C ++)
class IPrototype {
public:
virtual ~IPrototype() = default;
private:
virtual IPrototype* DoClone() const = 0;
virtual IPrototype* DoCreate() const = 0;
};
https://riptutorial.com/es/home 113
class ChildA : public A {
public:
auto Clone() const { return std::unique_ptr<ChildA>{DoClone()}; }
auto Create() const { return std::unique_ptr<ChildA>{DoCreate()}; }
private:
// Use covariant return type :)
ChildA* DoClone() const override { return new ChildA(*this); }
ChildA* DoCreate() const override { return new ChildA; }
};
ChildA childA;
A& a = childA;
IPrototype& prototype = a;
Patrón de prototipo (C #)
class Spoon {
}
class DessertSpoon : Spoon, ICloneable {
...
public object Clone() {
return this.MemberwiseClone();
}
}
class SoupSpoon : Spoon, ICloneable {
...
public object Clone() {
return this.MemberwiseClone();
}
}
En los lenguajes clásicos como Java, C # o C ++ comenzamos creando una clase y luego
podemos crear nuevos objetos de la clase o podemos extender la clase.
En JavaScript primero creamos un objeto, luego podemos aumentar el objeto o crear nuevos
objetos a partir de él. Así que creo, JavaScript demuestra prototipo real que el lenguaje clásico.
Ejemplo:
https://riptutorial.com/es/home 114
var myApp = myApp || {};
myApp.Customer.prototype = {
read: function (id) {
return "this is the customer with id = " + id;
},
update: function () {
return "customer updated";
},
remove: function () {
return "customer removed";
}
};
Aquí, creamos un objeto llamado Customer , y luego, sin crear un nuevo objeto , extendimos el
Customer object existente mediante la palabra clave prototipo . Esta técnica es conocida como
patrón prototipo .
https://riptutorial.com/es/home 115
Capítulo 28: pizarra
Examples
Muestra C #
Pizarra.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace Blackboard
{
public class BlackBoard
{
public List<KnowledgeWorker> knowledgeWorkers;
protected Dictionary<string, ControlData> data;
public Control control;
public BlackBoard()
{
this.knowledgeWorkers = new List<KnowledgeWorker>();
this.control = new Control(this);
this.data = new Dictionary<string, ControlData>();
}
https://riptutorial.com/es/home 116
this.data[key] = data;
}
else
{
this.data.Add(key, data);
}
}
}
}
Control.cs
using System;
using System.Collections.Generic;
namespace Blackboard
{
public class Control
{
BlackBoard blackBoard = null;
/// <summary>
/// Selects the next source of knowledge (knowledgeworker by inspecting the
blackgoard)
/// </summary>
void nextSource()
https://riptutorial.com/es/home 117
{
// observers the blackboard
foreach (KeyValuePair<string, ControlData> value in this.blackBoard.inspect())
{
if (value.Value.problem == "PrimeNumbers")
{
foreach (KnowledgeWorker worker in this.blackBoard.knowledgeWorkers)
{
if (worker.getName() == "PrimeFinder")
{
Console.WriteLine("Knowledge Worker Found");
worker.executeCondition();
worker.executeAction();
worker.updateBlackboard();
}
}
}
}
}
}
}
ControlData.cs
using System;
using System.Collections.Generic;
namespace Blackboard
{
public class ControlData:ICloneable
{
public string problem;
public object[] input;
public object[] output;
public string updateby;
public DateTime updated;
public ControlData()
{
this.problem = null;
this.input = this.output = null;
}
https://riptutorial.com/es/home 118
ControlData clone;
clone = new ControlData(this.problem, this.input);
clone.updated = this.updated;
clone.updateby = this.updateby;
clone.output = this.output;
return clone;
}
}
}
KnowledgeWorker.cs
namespace Blackboard {
/// <summary>
/// each knowledgeworker is resposible for knowing the conditions under which it can
contribute to a solution.
/// </summary>
abstract public class KnowledgeWorker
{
protected Boolean canContribute;
protected string Name;
public BlackBoard blackboard = null;
protected List<KeyValuePair<string, ControlData>> keys;
public KnowledgeWorker(BlackBoard blackboard, String Name)
{
this.blackboard = blackboard;
this.Name = Name;
}
} }
https://riptutorial.com/es/home 119
Capítulo 29: Principio de cierre abierto
Introducción
El principio de cierre abierto establece que el diseño y la escritura del código deben realizarse de
manera que se agreguen nuevas funciones con cambios mínimos en el código existente. El
diseño debe hacerse de manera que permita agregar nuevas funcionalidades como nuevas
clases, manteniendo el código existente sin cambios lo más posible. Las entidades de software
como clases, módulos y funciones deben estar abiertas para extensión pero cerradas para
modificaciones.
Observaciones
Como todo principio, el principio de cierre es solo un principio. Hacer un diseño flexible implica un
tiempo y un esfuerzo adicionales, e introduce un nuevo nivel de abstracción que aumenta la
complejidad del código. Por lo tanto, este principio debe aplicarse en aquellas áreas que tienen
más probabilidades de ser cambiadas. Hay muchos patrones de diseño que nos ayudan a
extender el código sin cambiarlo, por ejemplo, decorator.
Examples
Abrir Cerrar Principio de violación
/*
* This design have some major issues
* For each new shape added the unit testing
* of the GraphicEditor should be redone
* When a new type of shape is added the time
* for adding it will be high since the developer
* who add it should understand the logic
* of the GraphicEditor.
* Adding a new shape might affect the existing
* functionality in an undesired way,
* even if the new shape works perfectly
*/
class GraphicEditor {
public void drawShape(Shape s) {
if (s.m_type==1)
drawRectangle(s);
else if (s.m_type==2)
drawCircle(s);
}
public void drawCircle(Circle r) {....}
public void drawRectangle(Rectangle r) {....}
}
class Shape {
int m_type;
}
https://riptutorial.com/es/home 120
class Rectangle extends Shape {
Rectangle() {
super.m_type=1;
}
}
/*
* For each new shape added the unit testing
* of the GraphicEditor should not be redone
* No need to understand the sourcecode
* from GraphicEditor.
* Since the drawing code is moved to the
* concrete shape classes, it's a reduced risk
* to affect old functionallity when new
* functionallity is added.
*/
class GraphicEditor {
public void drawShape(Shape s) {
s.draw();
}
}
class Shape {
abstract void draw();
}
https://riptutorial.com/es/home 121
Capítulo 30: Publicar-Suscribir
Examples
Publicar-Suscribir en Java
Por lo general, hay un ContentServer que se ubica entre el editor y el suscriptor para ayudar a
mediar en la mensajería.
private ContentServer() {
this.subscriberLists = new Hashtable<>();
}
https://riptutorial.com/es/home 122
public Subscriber(Topic...topics) {
for (Topic t : topics) {
ContentServer.getInstance().registerSubscriber(this, t);
}
}
Por lo general, el patrón de diseño pub-sub se implementa teniendo en cuenta una vista de
multiproceso. Una de las implementaciones más comunes ve a cada Subscriber como un hilo
separado, con el ContentServer gestionando un grupo de hilos
Los editores y suscriptores no necesitan conocerse entre sí. Simplemente se comunican con la
ayuda de colas de mensajes.
(function () {
var data;
setTimeout(function () {
data = 10;
$(document).trigger("myCustomEvent");
}, 2000);
$(document).on("myCustomEvent", function () {
console.log(data);
});
})();
https://riptutorial.com/es/home 123
Capítulo 31: Semifallo
Observaciones
El patrón de diseño de Singleton a veces se considera como " patrón Anti ". Esto se debe al
hecho de que tiene algunos problemas. Tienes que decidir por ti mismo si crees que es apropiado
usarlo. Este tema ha sido discutido varias veces en StackOverflow.
Consulte: http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons
Examples
Singleton (C #)
Los Singletons se utilizan para garantizar que solo se está creando una instancia de un objeto. El
singleton permite que solo se cree una instancia de sí mismo, lo que significa que controla su
creación. El singleton es uno de los patrones de diseño de Gang of Four y es un patrón de
creación .
private Singleton()
{
}
return _instance;
}
https://riptutorial.com/es/home 124
}
Jon Skeet proporciona la siguiente implementación para un singleton perezoso y seguro para
subprocesos:
private Singleton()
{
}
}
Singleton (Java)
Los Singletons en Java son muy similares a C #, ya que ambos lenguajes están orientados a
objetos. A continuación se muestra un ejemplo de una clase singleton, donde solo una versión del
objeto puede estar activa durante la vida útil del programa (Suponiendo que el programa funcione
en un solo hilo)
private SingletonExample() { }
if (_instance == null) {
_instance = new SingletonExample();
}
return _instance;
}
}
private SingletonThreadSafeExample () { }
https://riptutorial.com/es/home 125
synchronized(SingletonThreadSafeExample.class) {
if (_instance == null) {
_instance = new SingletonThreadSafeExample();
}
}
}
}
Java también tiene un objeto llamado ThreadLocal , que crea una única instancia de un objeto en
una base hilo por hilo. Esto podría ser útil en aplicaciones donde cada hilo necesita su propia
versión del objeto.
private SingletonThreadLocalExample () { }
Aquí también hay una implementación de Singleton con enum (que contiene solo un elemento):
Cualquier implementación de clase Enum asegura que solo existirá una instancia de cada
elemento.
Bill Pugh Singleton Pattern es el enfoque más utilizado para la clase Singleton, ya que no requiere
sincronización
private SingletonExample(){}
https://riptutorial.com/es/home 126
con el uso de una clase estática interna privada, el titular no se carga en la memoria hasta que
alguien llame al método getInstance. La solución de Bill Pugh es segura para subprocesos y no
requiere sincronización.
Hay más ejemplos de Java singleton en el tema Singletons bajo la etiqueta de documentación de
Java.
Singleton (C ++)
Esto es necesario para crear exactamente un objeto para coordinar acciones en todo el sistema.
class Singleton
{
// Private constructor so it can not be arbitrarily created.
Singleton()
{}
// Disable the copy and move
Singleton(Singleton const&) = delete;
Singleton& operator=(Singleton const&) = delete;
public:
broadcastMessage : algunas veces, debe enviar un mensaje a todas las conexiones de clientes
https://riptutorial.com/es/home 127
suscritas.
No estoy proporcionando una implementación completa del código fuente ya que el ejemplo será
muy largo. A alto nivel, el código será así.
import java.util.*;
import java.net.*;
/* Lazy Singleton - Thread Safe Singleton without synchronization and volatile constructs */
final class LazyConnectionManager {
private Map<String,Connection> connections = new HashMap<String,Connection>();
private LazyConnectionManager() {}
public static LazyConnectionManager getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
private static final LazyConnectionManager INSTANCE = new LazyConnectionManager();
}
https://riptutorial.com/es/home 128
server:");
}
}catch(Exception err){
err.printStackTrace();
}
}
La siguiente implementación permite que solo un subproceso ingrese al área crítica, que el bloque
de bloqueo identifica, cuando aún no se ha creado una instancia de Singleton:
using System;
private Singleton() {}
https://riptutorial.com/es/home 129
return instance;
}
}
}
Este enfoque garantiza que solo se crea una instancia y solo cuando la instancia es necesaria.
Además, la variable se declara volátil para garantizar que la asignación a la variable de instancia
se complete antes de poder acceder a la variable de instancia. Por último, este enfoque utiliza
una instancia de syncRoot para bloquear, en lugar de bloquear el propio tipo, para evitar puntos
muertos.
Este enfoque de bloqueo de doble comprobación resuelve los problemas de concurrencia de hilos
al tiempo que evita un bloqueo exclusivo en cada llamada al método de propiedad de instancia.
También le permite retrasar la creación de instancias hasta que se acceda por primera vez al
objeto. En la práctica, una aplicación rara vez requiere este tipo de implementación. En la mayoría
de los casos, el enfoque de inicialización estática es suficiente.
Referencia: MSDN
Expresiones de gratitud
[Lea99] Lea, Doug. Programación concurrente en Java, Segunda Edición. Addison-Wesley, 1999.
Singleton (PHP)
Ejemplo de phptherightway.com
<?php
class Singleton
{
/**
* @var Singleton The reference to *Singleton* instance of this class
*/
private static $instance;
/**
* Returns the *Singleton* instance of this class.
*
* @return Singleton The *Singleton* instance.
*/
public static function getInstance()
{
if (null === static::$instance) {
static::$instance = new static();
}
return static::$instance;
https://riptutorial.com/es/home 130
}
/**
* Protected constructor to prevent creating a new instance of the
* *Singleton* via the `new` operator from outside of this class.
*/
protected function __construct()
{
}
/**
* Private clone method to prevent cloning of the instance of the
* *Singleton* instance.
*
* @return void
*/
private function __clone()
{
}
/**
* Private unserialize method to prevent unserializing of the *Singleton*
* instance.
*
* @return void
*/
private function __wakeup()
{
}
}
$obj = Singleton::getInstance();
var_dump($obj === Singleton::getInstance()); // bool(true)
$anotherObj = SingletonChild::getInstance();
var_dump($anotherObj === Singleton::getInstance()); // bool(false)
El problema principal con un singleton es el mismo que el problema con las variables globales.
Introducen el estado mutable global externo. Esto significa que las funciones que usan un
singleton no dependen únicamente de los parámetros de entrada, sino también del estado del
singleton. Esto significa que las pruebas pueden verse gravemente comprometidas (difíciles).
Los problemas con singletons pueden mitigarse usándolos junto con los patrones de creación;
https://riptutorial.com/es/home 131
para que la creación inicial del singleton pueda ser controlada.
https://riptutorial.com/es/home 132
Capítulo 32: SÓLIDO
Introducción
¿Qué es SOLID?
Que esperar:
Examples
SRP - Principio de responsabilidad única
Responsabilidad significa que en este contexto las razones para cambiar, por lo que el principio
establece que una clase solo debe tener una razón para cambiar.
También podría decir, no ponga funciones que cambien por diferentes motivos en la
misma clase.
Cuando cambia una clase puede afectar la funcionalidad relacionada con otras responsabilidades
de la clase. Mantener las responsabilidades en un nivel bajo minimiza el riesgo de efectos
secundarios.
Mal ejemplo
Tenemos una interfaz IWallet y una clase Wallet que implementa IWallet. The Wallet tiene nuestro
dinero y la marca, además, debe imprimir nuestro dinero como una representación de cadena. La
clase es utilizada por
https://riptutorial.com/es/home 133
1. un servicio web
2. un escritor de texto que imprime el dinero en euros en un archivo de texto.
Código de ejemplo C #
https://riptutorial.com/es/home 134
return m_Money;
}
Buen ejemplo
https://riptutorial.com/es/home 135
Para evitar la violación del SRP, eliminamos el método printMoney de la clase Wallet y lo
colocamos en una clase de impresora. La clase de Impresora ahora es responsable de la
impresión y la Cartera ahora es responsable del almacenamiento de los valores.
Código de ejemplo C #
https://riptutorial.com/es/home 136
{
//print euro
}
}
https://riptutorial.com/es/home 137
Creditos
S.
Capítulos Contributors
No
Cadena de
3 Ben Rhys-Lewis
responsabilidad
Inyección de
7 Kritner, matiaslauriti, user2321864
dependencia
Método de fábrica
8 abbath, Bongo
estático
10 Monostato skypjack
Patrón de Alexey Groshev, Arif, Daniel Käfer, fgb, Kyle Morgan, Ravindra
16
constructor babu, Sujit Kamthe, uzilan, Vasiliy Vlasov, yitzih
https://riptutorial.com/es/home 138
Aseem Bansal, dimitrisli, fabian, M.S. Dousti, Marek Skiba,
18 Patrón de estrategia matiaslauriti, Ravindra babu, Shog9, SjB, Stephen C,
still_learning, uzilan
Patrón de objeto
20 Jarod42, weston
nulo
Principio de cierre
28 Mher Didaryan
abierto
31 SÓLIDO Bongo
https://riptutorial.com/es/home 139