Peso mosca (patrón de diseño)

La versión actual de la página aún no ha sido revisada por colaboradores experimentados y puede diferir significativamente de la versión revisada el 4 de julio de 2016; las comprobaciones requieren 23 ediciones .
oportunista
peso mosca
Tipo de estructural
Descrito en Patrones de diseño

Un peso mosca ( eng.  flyweight , “lightweight (elemento)”) es un patrón de diseño estructural en el que un objeto que se presenta como una instancia única en diferentes lugares del programa, de hecho, no lo es.

Propósito

Optimización de la memoria al evitar la creación de instancias de elementos que tienen una entidad común.

Descripción

Flyweight se utiliza para reducir costos cuando se trata de una gran cantidad de objetos pequeños. Al diseñar un Flyweight, es necesario dividir sus propiedades en externas e internas. Las propiedades internas siempre permanecen sin cambios, mientras que las propiedades externas pueden diferir según el lugar y el contexto de aplicación y deben trasladarse fuera del instalador.

Flyweight complementa la plantilla de Factory Method de tal manera que cuando un cliente llama a un Factory Method para crear un nuevo objeto, busca un objeto ya creado con los mismos parámetros que el requerido y se lo devuelve al cliente. Si no existe tal objeto, la fábrica creará uno nuevo.

Ejemplos

Ejemplo de Python

Código fuente en Python class Lámpara ( objeto ): def __init__ ( self , color ): self . color = color clase LampFactory : lámparas = dict () @staticmethod def get_lamp ( color ): devuelve LampFactory . lámparas _ setdefault ( color , Lámpara ( color )) clase TreeBranch ( objeto ): def __init__ ( self , branch_number ): self . numero_sucursal = numero_sucursal def colgar ( self , lámpara ): print ( f "Colgar $ { lámpara . color } [$ { id ( lámpara ) } ] lámpara en rama $ { self . branch_number } [$ { id ( self ) } ]" ) clase ChristmasTree ( objeto ): def __init__ ( self ): self . lámparas_colgadas = 0 self . ramas = {} def get_branch ( self , número ): return self . ramas _ setdefault ( número , TreeBranch ( número )) def vestir_el_árbol ( self ): self . hang_lamp ( "rojo" , 1 ) self . hang_lamp ( "azul" , 1 ) self . hang_lamp ( "amarillo" , 1 ) self . hang_lamp ( "rojo" , 2 ) self . hang_lamp ( "azul" , 2 ) self . hang_lamp ( "amarillo" , 2 ) self . hang_lamp ( "rojo" , 3 ) self . hang_lamp ( "azul" , 3 ) self . hang_lamp ( "amarillo" , 3 ) self . hang_lamp ( "rojo" , 4 ) self . hang_lamp ( "azul" , 4 ) self . hang_lamp ( "amarillo" , 4 ) self . hang_lamp ( "rojo" , 5 ) self . hang_lamp ( "azul" , 5 ) self . hang_lamp ( "amarillo" , 5 ) self . hang_lamp ( "rojo" , 6 ) self . hang_lamp ( "azul" , 6 ) self . hang_lamp ( "amarillo" , 6 ) self . hang_lamp ( "rojo" , 7 ) self . hang_lamp ( "azul" , 7 ) self . hang_lamp ( "amarillo" , 7 ) def hang_lamp ( self , color , branch_number ): self . get_branch ( número_sucursal ) . colgar ( LampFactory . get_lamp ( color )) self . lámparas_colgadas += 1 if __name__ == '__main__' : ChristmasTree () . vestir_el_arbol ()

Ejemplo de Python (con anulación del constructor)

Código fuente de Python (con anulación del constructor) lámpara de clase ( objeto ): __instances = dict () def __nuevo__ ( cls , color ): devuelve cls . __instancias . setdefault ( color , super () . __nuevo__ ( cls )) def __init__ ( auto , color ): auto . color = color clase TreeBranch ( objeto ): def __init__ ( self , branch_number ): self . numero_sucursal = numero_sucursal def colgar ( self , lámpara ): print ( f "Colgar $ { lámpara . color } [$ { id ( lámpara ) } ] lámpara en rama $ { self . branch_number } [$ { id ( self ) } ]" ) clase ChristmasTree ( objeto ): def __init__ ( self ): self . lámparas_colgadas = 0 self . ramas = {} def get_branch ( self , número ): return self . ramas _ setdefault ( número , TreeBranch ( número )) def vestir_el_árbol ( self ): para rama en rango ( 1 , 8 ): para color en "rojo" , "azul" , "amarillo" : self . hang_lamp ( color , rama ) def hang_lamp ( self , color , branch_number ): self . get_branch ( número_sucursal ) . colgar ( Lámpara ( color )) uno mismo . lámparas_colgadas += 1 if __name__ == '__main__' : ChristmasTree () . vestir_el_arbol ()

Ejemplo #1 en Java

Fuente Java importar java.util.* ; enumeración pública FontEffect { NEGRITA , CURSIVA , SUPERSCRIPT , SUBSCRIPT , TACHADO } public final class FontData { /** * Un mapa hash débil eliminará las referencias no utilizadas a FontData. * Los valores deben estar envueltos en WeakReferences, * porque los objetos de valor en el mapa hash débil están sujetos a referencias fuertes. */ private static final WeakHashMap < FontData , WeakReference < FontData >> flyweightData = new WeakHashMap < FontData , WeakReference < FontData >> (); Tamaño del punto int final privado ; cara de fuente de cadena final privada ; color final privado color ; conjunto final privado < FontEffect > efectos ; private FontData ( int pointSize , String fontFace , Color color , EnumSet < FontEffect > efectos ) { this . tamañopunto = tamañopunto ; esto _ cara de fuente = cara de fuente ; esto _ color = color ; esto _ efectos = Colecciones . unmodificableSet ( efectos ); } Public static FontData create ( int pointSize , String fontFace , Color color , FontEffect ... efectos ) { EnumSet < FontEffect > EffectsSet = EnumSet . noneOf ( FontEffect . clase ); conjunto de efectos . addAll ( Arreglos . asList ( efectos )); // No nos preocupamos por el costo de creación de objetos, estamos reduciendo el consumo total de memoria FontData data = new FontData ( pointSize , fontFace , color , effectsSet ); if ( ! flyweightData . containsKey ( data )) { flyweightData . put ( datos , nueva referencia débil < FontData > ( datos )); } // devuelve la única copia inmutable con los valores dados devuelve flyweightData . obtener ( datos ). obtener (); } @Override public boolean equals ( Object obj ) { if ( obj instanceof FontData ) { if ( obj == this ) { return true ; } FontData otro = ( FontData ) obj ; devolver otro . tamañopunto == tamañopunto && otro . cara de fuente . es igual a ( fontFace ) && otro . color _ es igual a ( color ) && otro . efectos _ es igual ( efectos ); } devuelve falso ; } @Override public int hashCode () { return ( tamaño del punto * 37 + efectos . hashCode () * 13 ) * fontFace . código hash (); } // Getters para los datos de fuente, pero no setters. FontData es inmutable. }

Ejemplo #2 en Java

Fuente Java clase pública abstracta _ _ símbolo de carácter protegido ; ancho int protegido ; altura int protegida ; public abstract void printCharacter (); } public class CharacterA extiende EnglishCharacter { carácter público A () { símbolo = 'A' ; ancho = 10 ; altura = 20 ; } @Override public void printCharacter () { System . fuera _ println ( "Símbolo = " + símbolo + " Ancho = " + ancho + " Alto = " + alto ); } } public class CharacterB extiende EnglishCharacter { carácter público B () { símbolo = 'B' ; ancho = 20 ; altura = 30 ; } @Override public void printCharacter () { System . fuera _ println ( "Símbolo = " + símbolo + " Ancho = " + ancho + " Alto = " + alto ); } } public class CharacterC extiende EnglishCharacter { carácter público C () { símbolo = 'C' ; ancho = 40 ; altura = 50 ; } @Override public void printCharacter () { System . fuera _ println ( "Símbolo = " + símbolo + " Ancho = " + ancho + " Alto = " + alto ); } } public class FlyweightFactory { private HashMap < Integer , EnglishCharacter > caracteres = new HashMap (); public EnglishCharacter getCharacter ( int characterCode ){ EnglishCharacter character = caracteres . obtener ( código de carácter ); if ( carácter == nulo ){ cambiar ( código de carácter ){ caso 1 : { carácter = nuevo CarácterA (); romper ; } caso 2 : { carácter = nuevo CarácterB (); romper ; } caso 3 : { carácter = nuevo CarácterC (); romper ; } } caracteres . poner ( código de carácter , carácter ); } carácter de retorno ; } } /* * Una clase que muestra cómo funciona el patrón de diseño Flyweight. * */ Aplicación de clase pública { public static void main ( String [] args ){ FlyweightFactory factory = new FlyweightFactory (); int [] códigos de carácter = { 1 , 2 , 3 }; for ( int nextCode : characterCodes ){ EnglishCharacter character = factory . getCharacter ( siguienteCodigo ); personaje _ imprimirCaracter (); } } }

Ejemplo en C#

Texto fuente en C# utilizando el sistema ; utilizando System.Collections ; espacio de nombres peso mosca { class MainApp { static void Main () { // Crea un documento con la cadena de texto document = "AAZZBBZB" ; char [] chars = documento . ToCharArray (); Fábrica de Personajes f = nueva Fábrica de Personajes (); // estado extrínseco int pointSize = 10 ; // Para cada carácter use un objeto flyweight foreach ( char c in chars ) { pointSize ++; Carácter carácter = f . ObtenerCarácter ( c ); personaje _ Pantalla ( tamaño de punto ); } // Esperar a la Consola del usuario . leer (); } } // "Fábrica de Peso Mosca" class CharacterFactory { caracteres privados de Hashtable = new Hashtable (); public Character GetCharacter ( char key ) { // Usa "lazy initialization" Carácter character = caracteres [ clave ] como Carácter ; if ( carácter == nulo ) { cambiar ( tecla ) { caso 'A' : carácter = nuevo CarácterA (); romper ; caso 'B' : carácter = nuevo CarácterB (); romper ; //... case 'Z' : carácter = nuevo CarácterZ (); romper ; } caracteres . Añadir ( clave , carácter ); } carácter de retorno ; } } // "peso mosca" carácter de clase abstracta { símbolo de carácter protegido ; ancho int protegido ; altura int protegida ; ascenso int protegido ; descenso int protegido ; tamaño del punto int protegido ; Visualización de vacío virtual público ( int pointSize ) { this . tamañopunto = tamañopunto ; consola _ WriteLine ( este . símbolo + " (tamaño de punto " + este . tamaño de punto + ")" ); } } // "Peso mosca de hormigón" class CharacterA : Character { // Constructor public CharacterA () { this . símbolo = 'A' ; esto _ altura = 100 ; esto _ ancho = 120 ; esto _ ascender = 70 ; esto _ descenso = 0 ; } } // "Peso mosca de hormigón" class CharacterB : Character { // Constructor public CharacterB () { this . símbolo = 'B' ; esto _ altura = 100 ; esto _ ancho = 140 ; esto _ ascender = 72 ; esto _ descenso = 0 ; } } // ... C, D, E, etc. // "Peso mosca de hormigón" class CharacterZ : Character { // Constructor public CharacterZ () { this . símbolo = 'Z' ; esto _ altura = 100 ; esto _ ancho = 100 ; esto _ ascender = 68 ; esto _ descenso = 0 ; } } }

Ejemplo de C++

Texto fuente en C++ #incluir <mapa> #incluir <iostream> #include <memoria> // Carácter de clase "Peso mosca" { público : ~ Carácter virtual () = predeterminado ; visualización de vacío virtual () const = 0 ; protegido : char mSímbolo ; int mAncho ; int mAltura ; int mAascenso ; int mDescenso ; int mTamañoPunto ; }; // Clase "ConcreteFlyweight" ConcreteCharacter : carácter público { público : // Constructor ConcreteCharacter ( char aSymbol , int aPointSize ) { mSímbolo = aSímbolo ; mAncho = 120 ; mAltura = 100 ; mAascenso = 70 ; mDescenso = 0 ; mTamañoPunto = aTamañoPunto ; } // de Carácter virtual void display () const { std :: cout << mSymbol << " (TamañoPunto " << mTamañoPunto << " ) \n " ; } }; // plantilla "FlyweightFactory" < const int POINT_SIZE > clase CharacterFactory { público : const Carácter & getCharacter ( char aKey ) { // Utiliza caracteres de "inicialización diferida " :: const_iterator it = mCharacters . encontrar ( unaClave ); if ( mCaracteres . end () == it ) { mCharacters [ aKey ] = std :: make_unique < const ConcreteCharacter > ( aKey , POINT_SIZE ); return * mCaracteres [ unaClave ]; } más { volver * it -> segundo ; } } privado : usando Caracteres = std :: map < char , std :: unique_ptr < const Character > > ; Caracteres mCaracteres ; }; int principal (){ std :: stringdocument = " AAZZBBZB " ; Fábrica de personajes < 12 > Fábrica de personajes ; para ( automático : documento ) { auto && carácter = characterFactory . getCharacter ( eso ); personaje _ mostrar (); } devolver 0 ; }

Ejemplo de PHP5

codigo fuente php <?php // "FlyweightFactory" class CharacterFactory { private $caracteres = array (); public function GetCharacter ( $key ) { // Usa "inicialización diferida" if ( ! array_key_exists ( $key , $this -> caracteres )) { switch ( $key ) { case 'A' : $this -> caracteres [ $key ] = nuevo CarácterA (); romper ; case 'B' : $this -> caracteres [ $key ] = new CharacterB (); romper ; //... case 'Z' : $this -> caracteres [ $clave ] = new CharacterZ (); romper ; } } devuelve $esto -> caracteres [ $clave ]; } } // Clase abstracta "Peso mosca" Carácter { protected $símbolo ; protegido $ ancho ; altura protegida $ ; $ascenso protegido ; $descendencia protegida ; protegido $ tamaño del punto ; Visualización de la función abstracta pública ( $pointSize ); } // "Peso mosca de hormigón" class CharacterA extends Character { // Constructor public function __construct () { $this -> símbolo = 'A' ; $esto -> altura = 100 ; $esto -> ancho = 120 ; $esto -> ascenso = 70 ; $este -> descenso = 0 ; } public function Mostrar ( $pointSize ) { $this -> pointSize = $pointSize ; print ( $este -> símbolo . " (tamaño del punto " . $este -> tamaño del punto . ")" ); } } // "Peso mosca de hormigón" class CharacterB extends Character { // Constructor public function __construct () { $this -> símbolo = 'B' ; $esto -> altura = 100 ; $esto -> ancho = 140 ; $esto -> ascenso = 72 ; $este -> descenso = 0 ; } public function Mostrar ( $pointSize ) { $this -> pointSize = $pointSize ; print ( $este -> símbolo . " (tamaño del punto " . $este -> tamaño del punto . ")" ); } } // ... C, D, E, etc. // "Peso mosca de hormigón" class CharacterZ extends Character { // Constructor public function __construct () { $this -> símbolo = 'Z' ; $esto -> altura = 100 ; $esto -> ancho = 100 ; $esto -> ascenso = 68 ; $este -> descenso = 0 ; } public function Mostrar ( $pointSize ) { $this -> pointSize = $pointSize ; print ( $este -> símbolo . " (tamaño del punto " . $este -> tamaño del punto . ")" ); } } $documento = "AAZZBBZB" ; // Crea un documento con texto $chars = str_split ( $documento ); print_r ( $caracteres ); $f = nueva Fábrica de Personajes (); // estado extrínseco $pointSize = 0 ; // Para cada carácter use un objeto flyweight foreach ( $chars as $key ) { $pointSize ++ ; $carácter = $f -> ObtenerCarácter ( $clave ); $carácter -> Mostrar ( $puntoTamaño ); } ?>

Ejemplo de VB.NET

Código fuente en VB.NET Sistema de Importaciones.Cobranzas Peso mosca del espacio de nombres Class Program Shared Sub Main () ' Construye un documento con texto Dim document As String = "AAZZBBZB" Dim chars As Char () = document . ToCharArray () Dim f Como nuevo CharacterFactory () ' estado extrínseco Dim pointSize As Integer = 10 ' Para cada carácter, use un objeto de peso ligero Para cada c As Char In chars pointSize += 1 Dim character As Character = f . GetCharacter ( c ) carácter . Mostrar ( tamaño de punto ) Siguiente 'Esperar a la Consola del usuario . Lectura () End Sub End Class ' "FlyweightFactory" Class CharacterFactory Personajes privados como nueva tabla hash () Función pública GetCharacter ( tecla ByVal As Char ) As Character ' Usa "inicialización diferida" Dim character As Character = TryCast ( caracteres ( key ), Character ) Si el carácter no es nada , seleccione Case key Case " A "c character = New CharacterA () Salir Seleccionar Caso "B"c carácter = Nuevo CarácterB () Salir Seleccionar '... Caso "Z"c carácter = Nuevo CarácterZ () Salir Seleccionar Finalizar Seleccionar caracteres . Añadir ( tecla , carácter ) Finalizar si Retornar carácter Finalizar función Finalizar clase ' "Peso ligero" MustInherit Class Carácter Símbolo protegido As Char Ancho protegido As Integer Altura protegida As Integer Ascenso protegido As Integer Descenso protegido As Integer Tamaño de punto protegido As Integer Public MustOverride Sub Display ( ByVal pointSize As Integer ) End Class ' "ConcreteFlyweight" Class CharacterA Hereda Character ' Constructor Public Sub New () Me . símbolo = "A" c Yo . altura = 100 Me . ancho = 120 Me . ascenso = 70 Me . descenso = 0 End Sub Public Overrides Sub Display ( ByVal pointSize As Integer ) Me . tamañopunto = tamañopunto Consola . WriteLine ( Me . símbolo & " (tamaño de punto " & Me . tamaño de punto & ")" ) End Sub End Class ' "ConcreteFlyweight" Class CharacterB Hereda Character ' Constructor Public Sub New () Me . símbolo = "B" c Yo . altura = 100 Me . ancho = 140 Me . ascenso = 72 Yo . descenso = 0 End Sub Public Overrides Sub Display ( ByVal pointSize As Integer ) Me . tamañopunto = tamañopunto Consola . WriteLine ( Me . símbolo & " (tamaño de punto " & Me . tamaño de punto & ")" ) End Sub clase final '... C, D, E, etc. ' "ConcreteFlyweight" Class CharacterZ Hereda Character ' Constructor Public Sub New () Me . símbolo = "Z" c Yo . altura = 100 Me . ancho = 100 Me . ascenso = 68 Yo . descenso = 0 End Sub Public Overrides Sub Display ( ByVal pointSize As Integer ) Me . tamañopunto = tamañopunto Consola . WriteLine ( Me . símbolo & " (tamaño de punto " & Me . tamaño de punto & ")" ) End Sub End Class End Namespace

Ejemplo de rubí

código fuente rubí # Clase de objeto de instalación Lamp attr_reader :color #attr_reader hace que el atributo de color esté disponible fuera #de la clase llamando a .color en una instancia de Lamp def inicializar ( color ) @color = color final final clase TreeBranch def initialize ( branch_number ) @branch_number = branch_number end def hang ( lámpara ) pone "Colgar #{ lámpara . color } lámpara en la rama #{ @branch_number } " end end # Flyweight Factory class LampFactory def initialize @lamps = {} end def find_lamp ( color ) si @lamps . tiene_clave? ( color ) # si la lámpara ya existe, haga referencia a ella en lugar de crear una nueva lámpara = @lámparas [ color ] más lámpara = Lámpara . nuevo ( color ) @lamps [ color ] = final de lámpara final de lámpara def total_number_of_lamps_made @lamps . tamaño final final class ChristmasTree def initialize @lamp_factory = LampFactory . nuevo @lamps_hung = 0 dress_up_the_tree final def hang_lamp ( color , branch_number ) TreeBranch . nuevo ( número_sucursal ) . colgar ( @lamp_factory . find_lamp ( color )) @lamps_hung += 1 final def vestir_el_árbol lámpara_colgar ( 'rojo' , 1 ) lámpara_colgar ( 'azul' , 1 ) lámpara_colgar ( 'amarillo' , 1 ) lámpara_colgar ( 'rojo' , 2 ) lámpara_colgar ( 'azul' , 2 ) lámpara_colgar ( 'amarillo' , 2 ) lámpara_colgar ( 'rojo' , 3 ) lámpara_colgar ( 'azul' , 3 ) lámpara_colgar ( 'amarillo' , 3 ) lámpara_colgar ( 'rojo' , 4 ) lámpara_colgar ( 'azul' , 4 ) lámpara_colgar ( 'amarillo' , 4 ) lámpara_colgar ( 'rojo' , 5 ) lámpara_colgar ( 'azul' , 5 ) lámpara_colgar ( 'amarillo' , 5 ) lámpara_colgar ( 'rojo' , 6 ) lámpara_colgar ( 'azul' , 6 ) lámpara_colgar ( 'amarillo' , 6 ) lámpara_colgar ( 'rojo' ' , 7 ) lámpara_colgada ( 'azul' , 7 ) lámpara_colgada ( 'amarillo' , 7 ) pone "Hecho #{ @lamp_factory . número_total_de_lámparas_hechas } total de lámparas" end end

Símbolos en Smalltalk

Los caracteres en Smalltalk son casi idénticos a las "cadenas ordinarias", pero no se regeneran cada vez. De hecho, dos caracteres idénticos son siempre la misma instancia de la clase Símbolo, mientras que dos cadenas idénticas pueden ser instancias diferentes de la clase Cadena.

Enlaces