Fluevægt (designmønster)

Den aktuelle version af siden er endnu ikke blevet gennemgået af erfarne bidragydere og kan afvige væsentligt fra den version , der blev gennemgået den 4. juli 2016; checks kræver 23 redigeringer .
opportunist
Fluevægt
Type strukturel
Beskrevet i Design Patterns Ja

En flyweight ( eng.  flyweight , "lightweight (element)") er et strukturelt designmønster, hvor et objekt, der præsenterer sig selv som en unik instans forskellige steder i programmet, faktisk ikke er det.

Formål

Hukommelsesoptimering ved at forhindre oprettelsen af ​​forekomster af elementer, der har en fælles enhed.

Beskrivelse

Flyvevægt bruges til at reducere omkostningerne, når der skal håndteres et stort antal små genstande. Når man designer en fluevægter, er det nødvendigt at opdele dens egenskaber i ydre og indre. Indvendige egenskaber er altid uændrede, mens udvendige egenskaber kan variere afhængig af anvendelsessted og kontekst og skal flyttes uden for montøren.

Flyweight komplementerer fabriksmetodeskabelonen på en sådan måde, at når en klient kalder en fabriksmetode for at oprette et nyt objekt, søger den efter et allerede oprettet objekt med de samme parametre som det påkrævede og returnerer det til klienten. Hvis der ikke er et sådant objekt, vil fabrikken oprette et nyt.

Eksempler

Python-eksempel

Kildekode i Python klasse Lampe ( objekt ): def __init__ ( selv , farve ): selv . farve = farve klasse LampFactory : lamper = dict () @staticmethod def get_lamp ( farve ): returner LampFactory . lamper . setdefault ( farve , lampe ( farve )) klasse TreeBranch ( objekt ): def __init__ ( selv , branch_number ): selv . branch_number = branch_number def hænge ( selv , lampe ): print ( f "Hæng $ { lamp . color } [$ { id ( lamp ) } ] lampe på gren $ { self . branch_number } [$ { id ( self ) } ]" ) klasse Juletræ ( objekt ): def __init__ ( selv ): selv . lamps_hung = 0 self . grene = {} def get_branch ( selv , nummer ): returner selv . grene . setdefault ( nummer , TreeBranch ( nummer )) def dress_up_the_tree ( selv ): selv . hang_lamp ( "rød" , 1 ) self . hang_lamp ( "blå" , ​​1 ) selv . hang_lamp ( "gul" , 1 ) self . hang_lamp ( "rød" , 2 ) self . hang_lamp ( "blå" , ​​2 ) selv . hang_lamp ( "gul" , 2 ) self . hang_lamp ( "rød" , 3 ) self . hang_lamp ( "blå" , ​​3 ) selv . hang_lamp ( "gul" , 3 ) self . hang_lamp ( "rød" , 4 ) self . hang_lamp ( "blå" , ​​4 ) selv . hang_lamp ( "gul" , 4 ) self . hang_lamp ( "rød" , 5 ) self . hang_lamp ( "blå" , ​​5 ) selv . hang_lamp ( "gul" , 5 ) self . hang_lamp ( "rød" , 6 ) self . hang_lamp ( "blå" , ​​6 ) selv . hang_lamp ( "gul" , 6 ) self . hang_lamp ( "rød" , 7 ) self . hang_lamp ( "blå" , ​​7 ) selv . hang_lamp ( "gul" , 7 ) def hang_lamp ( selv , farve , branch_number ): selv . get_branch ( gren_nummer ) . hænge ( LampFactory . get_lamp ( farve )) self . lamper_hængt += 1 if __name__ == '__main__' : Juletræ () . klæde_op_træet ()

Python-eksempel (med konstruktørtilsidesættelse)

Python-kildekode (med konstruktørtilsidesættelse) klasse Lampe ( objekt ): __forekomster = dict () def __ny__ ( cls , farve ): returner cls . __forekomster . setdefault ( farve , super () . __ny__ ( cls )) def __init__ ( selv , farve ): selv . farve = farve klasse TreeBranch ( objekt ): def __init__ ( selv , branch_number ): selv . branch_number = branch_number def hænge ( selv , lampe ): print ( f "Hæng $ { lamp . color } [$ { id ( lamp ) } ] lampe på gren $ { self . branch_number } [$ { id ( self ) } ]" ) klasse Juletræ ( objekt ): def __init__ ( selv ): selv . lamps_hung = 0 self . grene = {} def get_branch ( selv , nummer ): returner selv . grene . setdefault ( nummer , TreeBranch ( nummer )) def dress_up_the_tree ( selv ): for gren i rækkevidde ( 1 , 8 ): for farve i "rød" , "blå" , "gul" : selv . hang_lamp ( farve , gren ) def hang_lamp ( selv , farve , branch_number ): selv . get_branch ( gren_nummer ) . hænge ( Lampe ( farve )) selv . lamper_hængt += 1 if __name__ == '__main__' : Juletræ () . klæde_op_træet ()

Eksempel #1 i Java

Java kilde importer java.util.* ; public enum FontEffect { BOLD , KURSIV , SUPERSCRIPT , SUBSCRIPT , STRIKETHROUGH } offentlig slutklasse FontData { /** * Et svagt hash-kort vil slette ubrugte referencer til FontData . * Værdier skal pakkes ind i WeakReferences, * fordi værdiobjekter i svagt hash-kort holdes af stærke referencer. */ private static final WeakHashMap < FontData , WeakReference < FontData >> flyweightData = new WeakHashMap < FontData , WeakReference < FontData >> (); privat endelig int pointSize ; privat endelig String fontFace ; privat endelig Farve farve ; private final Sæt < FontEffect > effekter ; private FontData ( int pointSize , String fontFace , Color color , EnumSet < FontEffect > effects ) { this . pointSize = pointSize ; dette . fontFace = fontFace ; dette . farve = farve ; dette . effekter = Samlinger . unmodificableSet ( effekter ); } public static FontData create ( int pointSize , String fontFace , Color color , FontEffect ... effekter ) { EnumSet < FontEffect > effectsSet = EnumSet . noneOf ( FontEffect . klasse ); effektsæt . addAll ( Arrays . asList ( effekter )); // Vi er ligeglade med omkostningerne til oprettelse af objekter, vi reducerer det samlede hukommelsesforbrug FontData data = new FontData ( pointSize , fontFace , color , effectsSet ); if ( ! flyweightData . containsKey ( data )) { flyweightData . put ( data , ny WeakReference < FontData > ( data )); } // returner den enkelte uforanderlige kopi med de givne værdier return flyweightData . ( data ). (); } @Override public boolean er lig med ( Object obj ) { if ( obj instansaf FontData ) { if ( obj == this ) { return true ; } FontData anden = ( FontData ) obj ; returnere andet . pointSize == pointSize && andet . fontFace . er lig med ( fontFace ) && andet . farve . er lig med ( farve ) && andet . effekter . er lig med ( effekter ); } returner falsk ; } @Override public int hashCode () { return ( pointSize * 37 + effekter . hashCode ( ) * 13 ) * fontFace . hashCode (); } // Getters for skrifttypedataene, men ingen sættere. FontData er uforanderlig. }

Eksempel #2 i Java

Java kilde offentlig abstrakt klasse _ _ beskyttet tegn symbol ; beskyttet int bredde ; beskyttet int højde ; offentlig abstrakt void printCharacter (); } public class CharacterA udvider EnglishCharacter { public CharacterA (){ symbol = 'A' ; bredde = 10 ; højde = 20 ; } @Override public void printCharacter () { System . ud . println ( "Symbol = " + symbol + " Bredde = " + bredde + " Højde = " + højde ); } } public class CharacterB udvider EnglishCharacter { public CharacterB (){ symbol = 'B' ; bredde = 20 ; højde = 30 ; } @Override public void printCharacter () { System . ud . println ( "Symbol = " + symbol + " Bredde = " + bredde + " Højde = " + højde ); } } public class CharacterC udvider EnglishCharacter { public CharacterC (){ symbol = 'C' ; bredde = 40 ; højde = 50 ; } @Override public void printCharacter () { System . ud . println ( "Symbol = " + symbol + " Bredde = " + bredde + " Højde = " + højde ); } } offentlig klasse FlyweightFactory { private HashMap < Integer , EnglishCharacter > characters = new HashMap (); public EnglishCharacter getCharacter ( int characterCode ){ EnglishCharacter character = characters . get ( tegnkode ); if ( karakter == null ){ switch ( characterCode ){ case 1 : { character = new CharacterA (); bryde ; } case 2 : { character = new CharacterB (); bryde ; } case 3 : { character = new CharacterC (); bryde ; } } tegn . put ( karakterkode , tegn ); } returtegn ; _ } } /* * En klasse, der viser, hvordan Flyweight-designmønsteret fungerer. * */ public class Application { public static void main ( String [] args ){ FlyweightFactory factory = new FlyweightFactory (); int [] karakterKoder = { 1 , 2 , 3 }; for ( int nextCode : characterCodes ){ Engelsk Character character = fabrik . getCharacter ( næstekode ); karakter . printkarakter (); } } }

Eksempel i C#

Kildetekst i C# bruger System ; ved hjælp af System.Collections ; navneområde Flyweight { class MainApp { static void Main () { // Byg et dokument med tekststreng document = "AAZZBBZB" ; char [] chars = dokument . ToCharArray (); CharacterFactory f = ny CharacterFactory (); // ydre tilstand int pointSize = 10 ; // For hver karakter skal du bruge et flyweight-objekt foreach ( char c in chars ) { pointSize ++; Tegnkarakter = f . _ GetCharacter ( c ); karakter . Display ( pointSize ); } // Vent på brugerkonsollen . læs (); } } // "FlyweightFactory" klasse CharacterFactory { private hashtable - tegn = ny hashtabel (); public Character GetCharacter ( char key ) { // Bruger "doven initialisering" Character character = characters [ key ] som Character ; if ( karakter == null ) { switch ( key ) { case 'A' : character = new CharacterA (); bryde ; case 'B' : karakter = nyt tegnB (); bryde ; //... case 'Z' : character = new CharacterZ (); bryde ; } tegn . Tilføj ( tast , tegn ); } returtegn ; _ } } // "fluevægt" abstrakt klasse Tegn { beskyttet tegn symbol ; beskyttet int bredde ; beskyttet int højde ; beskyttet int opstigning ; beskyttet int nedgang ; beskyttet int pointSize ; public virtual void Display ( int pointSize ) { this . pointSize = pointSize ; Konsol . WriteLine ( dette . symbol + " (pointsize " + this . pointSize + ")" ); } } // "Betonfluevægt" klasse CharacterA : Character { // Constructor public CharacterA () { this . symbol = 'A' ; dette . højde = 100 ; dette . bredde = 120 ; dette . stige = 70 ; dette . nedstigning = 0 ; } } // "Betonfluevægt" klasse CharacterB : Character { // Constructor public CharacterB () { this . symbol = 'B' ; dette . højde = 100 ; dette . bredde = 140 ; dette . stige = 72 ; dette . nedstigning = 0 ; } } // ... C, D, E osv. // "Betonfluevægt" class CharacterZ : Character { // Constructor public CharacterZ () { this . symbol = 'Z' ; dette . højde = 100 ; dette . bredde = 100 ; dette . stige = 68 ; dette . nedstigning = 0 ; } } }

C++ eksempel

Kildetekst i C++ #include <kort> #include <iostream> #inkluder <hukommelse> // "Flyweight" klasse Karakter { offentligt : virtuel ~ Tegn () = standard ; virtual void display () const = 0 ; beskyttet : char mSymbol ; int mWidth ; int mHøjde ; int mAscent ; int mDescent ; int mPointSize ; }; // "ConcreteFlyweight" klasse ConcreteCharacter : offentlig karakter { offentligt : // Constructor ConcreteCharacter ( char aSymbol , int aPointSize ) { mSymbol = aSymbol ; mBredde = 120 ; mHøjde = 100 ; mStigning = 70 ; mDescent = 0 ; mPointSize = aPointSize ; } // fra Character virtual void display () const { std :: cout << mSymbol << " ( PointSize " << mPointSize << " ) \n " ; } }; // "FlyweightFactory" skabelon < const int POINT_SIZE > klasse CharacterFactory { offentligt : const Character & getCharacter ( char aKey ) { // Bruger "doven initialisering" -tegn :: const_iterator it = mCharacters . find ( aNøgle ); if ( mCharacters . end () == it ) { mCharacters [ aKey ] = std :: make_unique < const ConcreteCharacter > ( aKey , POINT_SIZE ); return * mCharacters [ aKey ]; } andet { return * it -> sekund ; } } privat : ved at bruge Characters = std :: map < char , std :: unik_ptr < const Character > > ; Tegn mTegn ; }; int main (){ std :: stringdocument = " AAZZBBZB " ; CharacterFactory < 12 > characterFactory ; for ( auto it : dokument ){ auto && karakter = characterFactory . getCharacter ( it ); karakter . display (); } returnere 0 ; }

PHP5 eksempel

PHP kildekode <?php // "FlyweightFactory" klasse CharacterFactory { private $characters = array (); public function GetCharacter ( $key ) { // Bruger "doven initialisering" hvis ( ! array_key_exists ( $key , $this -> characters )) { switch ( $key ) { case 'A' : $this -> characters [ $key ] = nyt tegnA (); bryde ; case 'B' : $this -> tegn [ $key ] = nyt tegnB (); bryde ; //... case 'Z' : $this -> characters [ $key ] = new CharacterZ (); bryde ; } } returner $this -> tegn [ $key ]; } } // "Flyweight" abstrakt klasse Character { protected $symbol ; beskyttet $bredde ; beskyttet $højde ; beskyttet $opstigning ; beskyttet $nedstigning ; beskyttet $pointSize ; offentlig abstrakt funktion Display ( $pointSize ); } // "Betonfluevægt" klasse CharacterA udvider Character { // Konstruktør public function __construct () { $this -> symbol = 'A' ; $this -> højde = 100 ; $this -> bredde = 120 ; $this -> stigning = 70 ; $this -> descent = 0 ; } offentlig funktion Display ( $pointSize ) { $this -> pointSize = $pointSize ; print ( $this -> symbol . " (pointsize " . $this -> pointSize . ")" ); } } // "Betonfluevægt" klasse CharacterB udvider Character { // Konstruktor public function __construct () { $this -> symbol = 'B' ; $this -> højde = 100 ; $this -> bredde = 140 ; $this -> stigning = 72 ; $this -> descent = 0 ; } offentlig funktion Display ( $pointSize ) { $this -> pointSize = $pointSize ; print ( $this -> symbol . " (pointsize " . $this -> pointSize . ")" ); } } // ... C, D, E osv. // "Betonfluevægt" klasse CharacterZ udvider Character { // Konstruktor public function __construct () { $this -> symbol = 'Z' ; $this -> højde = 100 ; $this -> bredde = 100 ; $this -> stigning = 68 ; $this -> descent = 0 ; } offentlig funktion Display ( $pointSize ) { $this -> pointSize = $pointSize ; print ( $this -> symbol . " (pointsize " . $this -> pointSize . ")" ); } } $document = "AAZZBBZB" ; // Byg et dokument med teksten $chars = str_split ( $document ); print_r ( $tegn ); $f = ny CharacterFactory (); // ydre tilstand $pointSize = 0 ; // For hver karakter skal du bruge et flyweight-objekt foreach ( $chars som $key ) { $pointSize ++ ; $character = $f -> GetCharacter ( $key ); $character -> Display ( $pointSize ); } ?>

VB.NET eksempel

Kildekode i VB.NET Importer System.Samlinger Navneområde fluevægt Class Program Shared Sub Main () ' Byg et dokument med tekst Dim document As String = "AAZZBBZB" Dim chars As Char () = dokument . ToCharArray () Dim f As New CharacterFactory () ' ydre tilstand Dim pointSize Som heltal = 10 ' For hver karakter skal du bruge et fluevægtsobjekt For Hver c Som Tegn I tegn pointStørrelse += 1 Dim karakter Som Tegn = f . GetCharacter ( c ) tegn . Display ( pointSize ) Næste 'Vent på brugerkonsollen . Læs () End Sub End Class ' "FlyweightFactory" Klasse CharacterFactory Private karakterer som ny hashtabel () Offentlig funktion GetCharacter ( ByVal key As Character ) As Character ' Bruger "doven initialisering" Dæmpet tegn Som Character = TryCast ( tegn ( key ), Character ) Hvis tegnet ikke er noget , vælg Store og store bogstaver Store og små bogstaver "A"c tegn = New CharacterA () Afslut Vælg bogstav "B"c tegn = Nyt tegnB () Afslut Vælg '... Stort bogstav "Z"c tegn = Nyt tegnZ () Afslut Vælg Afslut Vælg tegn . Tilføj ( tast , tegn ) End If Returtegn End Function End Class _ ' "Flyweight" MustInherit Klasse Tegn Beskyttet symbol Som Char Beskyttet bredde Som heltal Beskyttet højde Som heltal Beskyttet opstigning Som heltal Beskyttet nedstigning Som heltal Beskyttet pointSize Som heltal Offentlig MustOverride Sub Display ( ByVal pointSize As Integer ) Slutklasse _ ' "ConcreteFlyweight" Klasse CharacterA arver karakter ' Constructor Public Sub New () Me . symbol = "A" c Me . højde = 100 Me . bredde = 120 Me . stigning = 70 Me . nedstigning = 0 End Sub Offentlige tilsidesættelser Undervisning ( ByVal pointSize Som heltal ) Mig . _ pointSize = pointSize- konsol . WriteLine ( Me . symbol & " (pointsize " & Me . pointSize & ")" ) End Sub End Class ' "ConcreteFlyweight" Klasse CharacterB arver karakter ' Constructor Public Sub New () Me . symbol = "B" c Me . højde = 100 Me . bredde = 140 Me . opstigning = 72 Me . nedstigning = 0 End Sub Offentlige tilsidesættelser Undervisning ( ByVal pointSize Som heltal ) Mig . _ pointSize = pointSize- konsol . WriteLine ( Me . symbol & " (pointsize " & Me . pointSize & ")" ) End Sub slutklasse _ ' ... C, D, E osv. ' "ConcreteFlyweight" Klasse CharacterZ arver karakter ' Constructor Public Sub New () Me . symbol = "Z" c Me . højde = 100 Me . bredde = 100 Me . opstigning = 68 Me . nedstigning = 0 End Sub Offentlige tilsidesættelser Undervisning ( ByVal pointSize Som heltal ) Mig . _ pointSize = pointSize- konsol . WriteLine ( Me . symbol & " (pointsize " & Me . pointSize & ")" ) End Sub End Class End Namespace

Ruby eksempel

Ruby kildekode # Facilitets objektklasse Lampe attr_reader :color #attr_reader gør farveattribut tilgængelig uden for #klassen ved at kalde .color på en lampeforekomst def initialize ( farve ) @color = farveslut ende _ klasse TreeBranch def initialize ( branch_number ) @ branch_number = branch_number end def hang ( lampe ) sætter "Hang #{ lamp . color } lamp on branch #{ @branch_number } " end end # Flyweight Factory class LampFactory def initialize @lamps = {} end def find_lampe ( farve ) hvis @lamps . har_nøgle? ( farve ) # hvis lampen allerede eksisterer, referer til den i stedet for at oprette en ny lampe = @lamper [ farve ] else lamp = Lampe . ny ( farve ) @lamper [ farve ] = lampe ende lampe ende def total_number_of_lamps_made @lamps . størrelse ende ende klasse ChristmasTree def initialize @lamp_factory = LampFactory . ny @lamps_hung = 0 dress_up_the_tree end def hang_lamp ( farve , branch_number ) TreeBranch . ny ( branch_number ) . hang ( @lamp_factory . find_lamp ( color )) @lamps_hung += 1 ende def dress_up_the_tree hang_lamp ( 'rød' , 1 ) hang_lamp ( 'blue' , 1 ) hang_lamp ( 'yellow' , 1 ) hang_lamp ( 'red' , 2 ) hang_lamp ( 'blue' , 2 ) hang_lamp ( 'yellow' , 2 ) hang_lamp ( 'red' , 3 ) hang_lamp ( 'blue' , 3 ) hang_lamp ( 'yellow' , 3 ) hang_lamp ( 'red' , 4 ) hang_lamp ( 'blue' , 4 ) hang_lamp ( 'yellow' , 4 ) hang_lamp ( 'red' , 5 ) hang_lamp ( 'blue' , 5 ) hang_lamp ( 'yellow' , 5 ) hang_lamp ( 'red' , 6 ) hang_lamp ( 'blue' , 6 ) hang_lamp ( 'yellow' , 6 ) hang_lamp ( 'red' ' , 7 ) hang_lamp ( 'blue' , 7 ) hang_lamp ( 'yellow' , 7 ) sætter "Made #{ @lamp_factory . total_number_of_lamps_made } total lamps" end

Symboler i Smalltalk

Karakterer i Smalltalk er næsten identiske med "almindelige strenge", men bliver ikke regenereret hver gang. To identiske tegn er faktisk altid den samme forekomst af Symbol-klassen, mens to identiske strenge kan være forskellige forekomster af String-klassen.

Links