En ingeniería de software , el patrón Twin es un patrón de diseño de software que permite a los desarrolladores modelar la herencia múltiple en lenguajes de programación que no la admiten. Este patrón evita muchos de los problemas que presenta la herencia múltiple. [1]
En lugar de tener una única clase derivada de dos superclases, se tienen dos subclases independientes, cada una derivada de una de las dos superclases. Estas dos subclases están estrechamente acopladas, por lo que ambas pueden considerarse como un objeto gemelo con dos extremos. [1]
El patrón gemelo se puede utilizar:
Habrá dos o más clases padre que se suelen heredar. Habrá subclases, cada una de las cuales se deriva de una de las superclases. Las subclases están vinculadas entre sí a través de campos, y cada subclase puede anular los métodos heredados de la superclase. Los nuevos métodos y campos suelen declararse en una subclase. [1]
El siguiente diagrama muestra la estructura típica de la herencia múltiple:
[1]
El siguiente diagrama muestra la estructura del patrón Twin después de reemplazar la estructura de herencia múltiple anterior:
[1]
Cada clase secundaria es responsable del protocolo heredado de su clase principal. Maneja los mensajes de este protocolo y reenvía otros mensajes a su clase asociada. [1]
Los clientes del patrón gemelo hacen referencia a uno de los objetos gemelos directamente y al otro a través de su campo gemelo. [1]
Los clientes que dependen de los protocolos de las clases padre se comunican con objetos de la respectiva clase hija. [1]
El siguiente código es un esquema de implementación de un tablero de juego de computadora con bolas en movimiento.
Clase para el tablero de juego:
clase pública Gameboard extiende Canvas { int público ancho , alto ; GameItem público firstItem ; … }
[1]
Boceto de código para la clase GameItem:
clase pública abstracta GameItem { Tablero de juego tablero ; int posX , posY ; GameItem siguiente ; vacío público abstracto dibujar (); vacío público abstracto hacer clic ( MouseEvent e ); booleano público abstracto intersecta ( GameItem otro ); vacío público abstracto colisionar con ( GameItem otro ); comprobación pública nula () { GameItem x ; para ( x = tablero . primerElemento ; x != null ; x = x . siguiente ) si ( interseca ( x )) colisionaCon ( x ); } public static BallItem newBall ( int posX , int posY , int radio ) { // método de GameBoard BallItem ballItem = new BallItem ( posX , posY , radio ); BallThread ballThread = new BallThread ( ) ; ballItem.twin = ballThread ; ballThread.twin = ballItem ; devolver ballItem ; } }
[1]
Boceto de código para la clase BallItem:
clase pública BallItem extiende GameItem { BallThread twin ; int radio ; int dx , dy ; booleano suspendido ; public void draw ( ) { board.getGraphics ( ) . drawOval ( posX - radio , posY - radio , 2 * radio , 2 * radio ); } público void mover () { posX += dx ; posY += dy ; } public void click () { if ( suspendido ) twin . resume (); else twin . suspend (); suspendido = ! suspendido ; } público booleano intersecta ( GameItem otro ) { si ( otra instancia de Muro ) devuelve posX - radio <= otro . posX && otro . posX <= posX + radio || posY - radio <= otro . posY && otro . posY <= posY + radio ; de lo contrario devuelve falso ; } public void collideWith ( GameItem other ) { Muro muro = ( Muro ) otro ; si ( pared . esVertical ) dx = - dx ; de lo contrario dy = - dy ; } }
[1]
Boceto de código para la clase BallThread:
clase pública BallThread extiende Thread { BallItem gemelo ; public void run () { while ( true ) { twin.draw ( ); / * borrar*/ twin.mover ( ); twin.draw ( ) ; } } }
[1]
Se deben considerar las siguientes cuestiones: