Greutatea muștei (model de design)

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită la 4 iulie 2016; verificările necesită 23 de modificări .
oportunist
Greutatea muștei
Tip de structural
Descris în Design Patterns da

Un flyweight ( eng.  flyweight , „lightweight (element)”) este un model de proiectare structurală în care un obiect care se prezintă ca o instanță unică în diferite locuri din program, de fapt, nu este.

Scop

Optimizarea memoriei prin prevenirea creării de instanțe ale elementelor care au o entitate comună.

Descriere

Flyweight este folosit pentru a reduce costurile atunci când aveți de-a face cu un număr mare de obiecte mici. Atunci când proiectați un Flyweight, este necesar să-i împărțiți proprietățile în externe și interne. Proprietățile interne rămân întotdeauna neschimbate, în timp ce proprietățile externe pot diferi în funcție de locul și contextul de aplicare și trebuie mutate în afara instalatorului.

Flyweight completează șablonul Factory Method în așa fel încât atunci când un client apelează o Factory Method pentru a crea un nou obiect, caută un obiect deja creat cu aceiași parametri ca și cel necesar și îl returnează clientului. Dacă nu există un astfel de obiect, fabrica va crea unul nou.

Exemple

Exemplu Python

Cod sursă în Python clasă Lampă ( obiect ): def __init__ ( self , color ): self . culoare = culoare clasă LampFactory : lămpi = dict () @staticmethod def get_lamp ( culoare ): return LampFactory . lămpi . setdefault ( culoare , Lampă ( culoare )) clasa TreeBranch ( obiect ): def __init__ ( self , branch_number ): self . ramură_număr = ramură_număr def hang ( self , lamp ): print ( f "Hang $ { lamp . color } [$ { id ( lamp ) } ] lamp on branch $ { self . branch_number } [$ { id ( self ) } ]" ) clasa Pomul de Crăciun ( obiect ): def __init__ ( self ): self . lamps_hung = 0 self . ramuri = {} def get_branch ( self , number ): return self . ramuri . setdefault ( număr , TreeBranch ( număr )) def dress_up_the_tree ( self ): sine . hang_lamp ( "roșu" , 1 ) self . hang_lamp ( „albastru” , ​​1 ) sine . hang_lamp ( "galben" , 1 ) self . hang_lamp ( "roșu" , 2 ) self . hang_lamp ( „albastru” , ​​​2 ) sine . hang_lamp ( "galben" , 2 ) self . hang_lamp ( "roșu" , 3 ) self . hang_lamp ( „albastru” , ​​3 ) sine . hang_lamp ( "galben" , 3 ) self . hang_lamp ( "roșu" , 4 ) self . hang_lamp ( „albastru” , ​​​4 ) sine . hang_lamp ( "galben" , 4 ) self . hang_lamp ( "roșu" , 5 ) self . hang_lamp ( "albastru" , ​​​5 ) sine . hang_lamp ( "galben" , 5 ) self . hang_lamp ( "roșu" , 6 ) self . hang_lamp ( „albastru” , ​​​6 ) sine . hang_lamp ( "galben" , 6 ) self . hang_lamp ( "roșu" , 7 ) self . hang_lamp ( "albastru" , ​​7 ) sine . hang_lamp ( "galben" , 7 ) def hang_lamp ( self , color , branch_number ): self . obține_ramură ( număr_ramură ) . hang ( LampFactory . get_lamp ( culoare )) sine . lămpi_atârnate += 1 if __name__ == '__main__' : Pomul de Crăciun () . îmbracă_copacul ()

Exemplu Python (cu anularea constructorului)

Cod sursă Python (cu înlocuirea constructorului) clasă Lampă ( obiect ): __instances = dict () def __new__ ( cls , culoare ): return cls . __instanțe . setdefault ( culoare , super () . __new__ ( cls )) def __init__ ( self , color ): self . culoare = culoare clasa TreeBranch ( obiect ): def __init__ ( self , branch_number ): self . ramură_număr = ramură_număr def hang ( self , lamp ): print ( f "Hang $ { lamp . color } [$ { id ( lamp ) } ] lamp on branch $ { self . branch_number } [$ { id ( self ) } ]" ) clasa Pomul de Crăciun ( obiect ): def __init__ ( self ): self . lamps_hung = 0 self . ramuri = {} def get_branch ( self , number ): return self . ramuri . setdefault ( număr , TreeBranch ( număr )) def dress_up_the_tree ( self ): pentru ramura din interval ( 1 , 8 ): pentru culoare în „roșu” , „albastru” , ​​”galben” : sine . hang_lamp ( culoare , ramură ) def hang_lamp ( self , color , branch_number ): self . obține_ramură ( număr_ramură ) . atârnă ( Lampă ( culoare )) sine . lămpi_atârnate += 1 if __name__ == '__main__' : Pomul de Crăciun () . îmbracă_copacul ()

Exemplul #1 în Java

Sursa Java import java.util.* ; public enum FontEffect { BOLD , ITALIC , SUPERSCRIPT , SUBSCRIPT , STRIKETHROUGH } public final class FontData { /** * O hartă hash slabă va elimina referințele neutilizate la FontData. * Valorile trebuie să fie împachetate în WeakReferences, * deoarece obiectele de valoare din harta hash slabă sunt deținute de referințe puternice. */ private static final WeakHashMap < FontData , WeakReference < FontData >> flyweightData = new WeakHashMap < FontData , WeakReference < FontData >> (); private final int pointSize ; private final String fontFace ; culoare finală privată ; _ Private final Set < FontEffect > efecte ; private FontData ( int pointSize , String fontFace , Color color , EnumSet < FontEffect > efecte ) { aceasta . pointSize = pointSize ; aceasta . fontFace = fontFace ; aceasta . culoare = culoare ; aceasta . efecte = Colecții . unmodiableSet ( efecte ); } public static FontData create ( int pointSize , String fontFace , Color color , FontEffect ... efecte ) { EnumSet < FontEffect > effectsSet = EnumSet . noneOf ( FontEffect . class ); set de efecte . addAll ( Arrays . asList ( efecte )); // Nu suntem preocupați de costul de creare a obiectelor, reducem consumul total de memorie FontData data = new FontData ( pointSize , fontFace , color , effectsSet ); if ( ! flyweightData . containsKey ( data )) { flyweightData . put ( date , nou WeakReference < FontData > ( date )); } // returnează singura copie imuabilă cu valorile date return flyweightData . obține ( date ). obține (); } @Override public boolean equals ( Object obj ) { if ( obj instanceof FontData ) { if ( obj == this ) { return true ; } FontData other = ( FontData ) obj ; returnează altele . pointSize == pointSize && altele . fontFace . este egal cu ( fontFace ) && altele . culoare . egal ( culoare ) && altele . efecte . egal ( efecte ); } return false ; } @Override public int hashCode () { return ( pointSize * 37 + efecte . hashCode () * 13 ) * fontFace . hashCode (); } // Getters pentru datele fontului, dar nu setters. FontData este imuabil. }

Exemplul #2 în Java

Sursa Java clasa public abstract _ _ simbol char protejat ; protected int width ; protected int inaltime ; public abstract void printCharacter (); } Clasa publică CharacterA extinde limba englezăCharacter { Public CharacterA (){ simbol = 'A' ; latime = 10 ; inaltime = 20 ; } @Override public void printCharacter () { System . afară . println ( "Simbol = " + simbol + " Latime = " + latime + " Inaltime = " + inaltime ); } } Clasa publică Caracterul B extinde caracterul englezesc { public CharacterB (){ simbol = 'B' ; latime = 20 ; inaltime = 30 ; } @Override public void printCharacter () { System . afară . println ( "Simbol = " + simbol + " Latime = " + latime + " Inaltime = " + inaltime ); } } Clasa publică CharacterC extinde EnglishCharacter { public CharacterC (){ simbol = 'C' ; latime = 40 ; inaltime = 50 ; } @Override public void printCharacter () { System . afară . println ( "Simbol = " + simbol + " Latime = " + latime + " Inaltime = " + inaltime ); } } clasă publică FlyweightFactory { private HashMap < Integer , EnglishCharacter > caractere = new HashMap (); public EnglishCharacter getCharacter ( int characterCode ){ EnglishCharacter caracter = caractere . get ( caracterCod ); if ( caracter == null ){ comutare ( caracterCod ){ cazul 1 : { caracter = caracter nouA ( ); rupe ; } cazul 2 : { caracter = caracter nou B (); rupe ; } cazul 3 : { caracter = new CharacterC (); rupe ; } } caractere . put ( caracterCod , caracter ); } caracter de returnare ; } } /* * O clasă care arată cum funcționează modelul de design Flyweight. * */ Aplicație de clasă publică { public static void main ( String [] args ){ FlyweightFactory factory = new FlyweightFactory (); int [] characterCodes = { 1 , 2 , 3 }; for ( int nextCode : characterCodes ){ EnglishCharacter character = factory . getCharacter ( nextCode ); caracter . printCharacter (); } } }

Exemplu în C#

Text sursă în C# folosind System ; folosind System.Collections ; spatiu de nume Flyweight { class MainApp { static void Main () { // Construiește un document cu șir de text document = "AAZZBBZB" ; char [] chars = document . ToCharArray (); CharacterFactory f = new CharacterFactory (); // stare extrinsecă int pointSize = 10 ; // Pentru fiecare caracter folosiți un obiect cu greutatea muștei foreach ( char c in chars ) { pointSize ++; Caracter caracter = f . GetCharacter ( c ); caracter . Display ( pointSize ); } // Așteptați Consola utilizatorului . citește (); } } // „FlyweightFactory” class CharacterFactory { private Hashtable characters = new Hashtable (); public Character GetCharacter ( cheie caracter ) { // Folosește „inițializarea leneșă” Caracter caracter = caractere [ cheie ] ca caracter ; if ( caracter == null ) { comutator ( tasta ) { case 'A' : caracter = caracter nou A (); rupe ; case 'B' : caracter = caracter nou B (); rupe ; //... case 'Z' : caracter = new CharacterZ (); rupe ; } caractere . Adăugați ( cheie , caracter ); } caracter de returnare ; } } // "greutatea musca" abstract class Character { protected char symbol ; protected int width ; protected int inaltime ; protejat int urcare ; protected int descend ; protected int pointSize ; public virtual void Display ( int pointSize ) { this . pointSize = pointSize ; Consola . WriteLine ( acest simbol . + " (dimensiunea punctului " + acest .pointSize + " ) " ); } } // „ConcreteFlyweight” class CharacterA : Character { // Constructor public CharacterA () { this . simbol = 'A' ; aceasta . inaltime = 100 ; aceasta . latime = 120 ; aceasta . urcare = 70 ; aceasta . coborâre = 0 ; } } // „ConcreteFlyweight” class CharacterB : Character { // Constructor public CharacterB () { this . simbol = 'B' ; aceasta . inaltime = 100 ; aceasta . latime = 140 ; aceasta . urcare = 72 ; aceasta . coborâre = 0 ; } } // ... C, D, E etc. // „ConcreteFlyweight” class CharacterZ : Character { // Constructor public CharacterZ () { this . simbol = 'Z' ; aceasta . inaltime = 100 ; aceasta . latime = 100 ; aceasta . urcare = 68 ; aceasta . coborâre = 0 ; } } }

Exemplu C++

Text sursă în C++ #include <hartă> #include <iostream> #include <memorie> // Clasa „Flyweight” Caracter { public : virtual ~ Caracter () = implicit ; virtual void display () const = 0 ; protejat : char mSymbol ; int mWidth ; int mHeight ; int mAscent ; int mDescent ; int mPointSize ; }; // Clasa "ConcreteFlyweight" ConcreteCharacter : caracter public { public : // Constructor ConcreteCharacter ( char aSymbol , int aPointSize ) { mSymbol = aSimbol ; mWidth = 120 ; m Înălțime = 100 ; mAscent = 70 ; mCoborâre = 0 ; mPointSize = aPointSize ; } // din caracterul virtual void display () const { std :: cout << mSymbol << " ( PointSize " << mPointSize << " ) \n " ; } }; // Șablon „FlyweightFactory” < const int POINT_SIZE > clasa CharacterFactory { public : const Character & getCharacter ( char aKey ) { // Folosește "inițializarea leneșă" Caractere :: const_iterator it = mCaractere . găsi ( aKey ); if ( mCaractere . end () == it ) { mCaractere [ aKey ] = std :: make_unique < const ConcreteCharacter > ( aKey , POINT_SIZE ); returnează * mCaractere [ aKey ]; } altfel { return * it -> secunda ; } } privat : folosind Caractere = std :: map < char , std :: unique_ptr < const Character > > ; Caractere mCaractere ; }; int main (){ std :: stringdocument = " AAZZBBZB " ; CharacterFactory < 12 > characterFactory ; pentru ( auto it : document ){ auto && caracter = characterFactory . getCharacter ( it ); caracter . afișaj (); } returnează 0 ; }

Exemplu PHP5

Cod sursă PHP <?php // Clasa "FlyweightFactory" CharacterFactory { private $caractere = matrice (); funcția publică GetCharacter ( $key ) { // Folosește „inițializarea leneșă” dacă ( ! array_key_exists ( $key , $this -> caractere )) { switch ( $key ) { case 'A' : $this -> caractere [ $key ] = caracter nouA ( ); rupe ; case 'B' : $this -> caractere [ $key ] = new CharacterB (); rupe ; //... case 'Z' : $acest -> caractere [ $key ] = new CharacterZ (); rupe ; } } returnează $this -> caractere [ $key ]; } } // Clasa abstractă „Flyweight” Caracter { protected $simbol ; protejat $width ; protected $height ; protejat $ascensiunea ; protejat $descent ; protejat $pointSize ; funcția abstractă publică Display ( $pointSize ); } // „ConcreteFlyweight” class CharacterA extins Character { // Constructor public function __construct () { $this -> simbol = 'A' ; $this -> inaltime = 100 ; $this -> latime = 120 ; $this -> urcare = 70 ; $aceasta -> coborâre = 0 ; } funcția publică Display ( $pointSize ) { $this -> pointSize = $punctSize ; print ( $this -> simbol . " (pointsize " . $this -> pointSize . ")" ); } } // „ConcreteFlyweight” class CharacterB extinde Caracterul { // Constructor public function __construct () { $this -> simbol = 'B' ; $this -> inaltime = 100 ; $this -> latime = 140 ; $this -> urcare = 72 ; $aceasta -> coborâre = 0 ; } funcția publică Display ( $pointSize ) { $this -> pointSize = $punctSize ; print ( $this -> simbol . " (pointsize " . $this -> pointSize . ")" ); } } // ... C, D, E etc. // „ConcreteFlyweight” class CharacterZ extinde Character { // Constructor public function __construct () { $this -> simbol = 'Z' ; $this -> inaltime = 100 ; $this -> latime = 100 ; $this -> urcare = 68 ; $aceasta -> coborâre = 0 ; } funcția publică Display ( $pointSize ) { $this -> pointSize = $punctSize ; print ( $this -> simbol . " (pointsize " . $this -> pointSize . ")" ); } } $document = "AAZZBBZB" ; // Construiește un document cu text $cars = str_split ( $document ); print_r ( $caractere ); $f = new CharacterFactory (); // stare extrinsecă $pointSize = 0 ; // Pentru fiecare personaj folosiți un obiect cu greutatea muștei foreach ( $caracterele ca $key ) { $pointSize ++ ; $caracter = $f -> GetCharacter ( $cheie ); $caracter -> Afișare ( $pointSize ); } ?>

Exemplu VB.NET

Cod sursă în VB.NET Sistem de importuri.Colectii Spațiu de nume Flyweight Class Program Shared Sub Main () ' Creați un document cu text Dim document As String = "AAZZBBZB" Dim chars As Char () = document . ToCharArray () Dim f ca nou CharacterFactory () ' stare extrinsecă Dim pointSize As Integer = 10 ' Pentru fiecare personaj utilizați un obiect cu greutatea muștei Pentru fiecare c As Char În caractere pointSize += 1 Dim character As Character = f . GetCharacter ( c ) caracter . Afișează ( pointSize ) În continuare ' Așteptați Consola utilizator . Citiți () End Sub End Class Clasa „FlyweightFactory” CharacterFactory Caractere private ca noua tabelă hash () Funcție publică GetCharacter ( Tasta ByVal As Character ) As Character ' Folosește „inițializarea leneșă” caracterul Dim As Character = TryCast ( caractere ( tasta ), Character ) Dacă caracterul nu este nimic , atunci Selectați Tasta majuscule și majuscule Caracterul „ A ”c = Caracter nouA () Ieșire Selectare Caracter "B"c = Caracter nou B () Ieșire Selectare '... Caracter " Z" c = Caracter nouZ ( ) Ieșire Selectare Sfârșit Selectare caractere . Adăugați ( cheie , caracter ) End If Returnează caracterul End Function End Class ' "Flyweight" MustInherit Clasa Caracter Simbol protejat Ca Char Lățimea protejată Ca întreg Înălțimea protejată Ca întreg Urcarea protejată Ca întreg Coborârea protejată Ca întreg Punctul protejat Dimensiunea Ca întreg Public MustOverride Sub Display ( ByVal pointSize As Integer ) Clasa finală ' "ConcreteFlyweight" Clasa CaracterulA moștenește caracterul ' Constructor Public Sub Nou () Eu . simbol = "A" c Eu . inaltime = 100 Me . latime = 120 Me . urcare = 70 Me . descent = 0 End Sub Public Overscrie Sub Display ( ByVal pointSize As Integer ) Eu . pointSize = pointSize Consola . WriteLine ( Me . simbol & " (pointsize " & Me . pointSize & ")" ) End Sub End Class ' "ConcreteFlyweight" Clasa CharacterB Moștenește caracterul ' Constructor Public Sub Nou () Eu . simbol = "B" c Me . inaltime = 100 Me . latime = 140 Me . urcare = 72 Me . descent = 0 End Sub Public Overscrie Sub Display ( ByVal pointSize As Integer ) Eu . pointSize = pointSize Consola . WriteLine ( Me . simbol & " (pointsize " & Eu . pointSize & ")" ) End Sub termina clasa ' ... C, D, E etc. ' Clasa "ConcreteFlyweight" CharacterZ Moștenește caracterul ' Constructor Public Sub Nou () Eu . simbol = "Z" c Me . inaltime = 100 Me . latime = 100 Me . urcare = 68 Me . descent = 0 End Sub Public Overscrie Sub Display ( ByVal pointSize As Integer ) Eu . pointSize = pointSize Consola . WriteLine ( Me . simbol & " (pointsize " & Eu . pointSize & ")" ) End Sub End Class End Namespace

Exemplu Ruby

Cod sursă Ruby # Clasa de obiecte facilitate Lamp attr_reader :color #attr_reader face ca atributul de culoare să fie disponibil în afara clasei, apelând .color pe o instanță Lamp def initialize ( culoare ) @color = finalul culorii _ clasa TreeBranch def initialize ( branch_number ) @branch_number = branch_number end def hang ( lampă ) pune „Hang #{ lamp . color } lamp on branch #{ @branch_number } end end # Flyweight Factory clasă LampFactory def initialize @lamps = {} end def find_lamp ( culoare ) dacă @lamps . are_cheie? ( culoare ) # dacă lampa există deja, referiți-o în loc să creați o lampă nouă = @lamps [ color ] else lamp = Lamp . new ( culoare ) @lamps [ culoare ] = lamp end lamp end def total_number_of_lamps_made @lamps . dimensiune capăt capăt clasa ChristmasTree def initialize @lamp_factory = LampFactory . nou @lamps_hung = 0 îmbracă_sfârşitul_copacului _ def hang_lamp ( culoare , branch_number ) TreeBranch . nou ( număr_sucursală ) . hang ( @lamp_factory . find_lamp ( culoare )) @lamps_hung += 1 capăt def dress_up_the_tree hang_lamp ( 'rosu' , 1 ) hang_lamp ( 'albastru' , 1 ) hang_lamp ( 'galben' , 1 ) hang_lamp ( 'rosu' , 2 ) hang_lamp ( 'albastru' , 2 ) hang_lamp ( ' , 2 ) hang_lamp (' 2 hang_lamp ( 'rosu' , 3 ) hang_lamp ( 'albastru' , 3 ) hang_lamp ( 'galben' , 3 ) hang_lamp ( 'rosu' , 4 ) hang_lamp ( 'albastru' , 4 ) hang_lamp ( 'galben' , 4 lampa ( ) 'roșu' , 5 ) hang_lamp ( 'albastru' , 5 ) hang_lamp ( 'galben' , 5 ) hang_lamp ( 'roșu' , 6 ) hang_lamp ( 'albastru' , 6 ) hang_lamp ( 'galben' , 6 ) hang_lamp ( 'rosu' ) ' , 7 ) hang_lamp ( 'albastru' , 7 ) hang_lamp ( 'yellow' , 7 ) pune "Made #{ @lamp_factory . total_number_of_lamps_made } total lamps" end end

Simboluri în Smalltalk

Caracterele din Smalltalk sunt aproape identice cu „șirurile obișnuite”, dar nu sunt regenerate de fiecare dată. Două caractere identice sunt de fapt întotdeauna aceeași instanță a clasei Symbol, în timp ce două șiruri identice pot fi instanțe diferite ale clasei String.

Link -uri