Flugvikt (designmönster)

Den aktuella versionen av sidan har ännu inte granskats av erfarna bidragsgivare och kan skilja sig väsentligt från versionen som granskades den 4 juli 2016; kontroller kräver 23 redigeringar .
opportunistisk
Flugvikt
Sorts strukturell
Beskrivs i Design Patterns Ja

En flugvikt ( eng.  flugvikt , "lättvikt (element)") är ett strukturellt designmönster där ett objekt som presenterar sig som en unik instans på olika platser i programmet faktiskt inte är det.

Syfte

Minnesoptimering genom att förhindra skapandet av instanser av element som har en gemensam enhet.

Beskrivning

Flugvikt används för att minska kostnaderna vid hantering av ett stort antal små föremål. När du designar en flugviktare är det nödvändigt att dela in dess egenskaper i externa och interna. Invändiga egenskaper är alltid oförändrade medan yttre egenskaper kan skilja sig beroende på plats och sammanhang för applikationen och måste flyttas utanför montören.

Flyweight kompletterar Factory Method- mallen på ett sådant sätt att när en klient anropar en Factory Method för att skapa ett nytt objekt, letar den efter ett redan skapat objekt med samma parametrar som det krävs och returnerar det till klienten. Om det inte finns något sådant objekt kommer fabriken att skapa ett nytt.

Exempel

Python-exempel

Källkod i Python klass Lampa ( objekt ): def __init__ ( själv , färg ): själv . färg = färg klass LampFactory : lampor = dict () @staticmethod def get_lamp ( färg ): returnera LampFactory . lampor . setdefault ( färg , lampa ( färg )) klass TreeBranch ( objekt ): def __init__ ( self , branch_number ): self . branch_number = branch_number def hang ( själv , lampa ): print ( f "Häng $ { lamp . color } [$ { id ( lamp ) } ] lampa på gren $ { self . branch_number } [$ { id ( self ) } ]" ) klass Julgran ( objekt ): def __init__ ( själv ): själv . lamps_hung = 0 själv . grenar = {} def get_branch ( själv , nummer ): returnera själv . grenar . setdefault ( nummer , TreeBranch ( nummer )) def dress_up_the_tree ( själv ): själv . hang_lamp ( "röd" , 1 ) själv . hang_lamp ( "blå" , ​​1 ) själv . hang_lamp ( "gul" , 1 ) själv . hang_lamp ( "röd" , 2 ) själv . hang_lamp ( "blå" , ​​2 ) själv . hang_lamp ( "gul" , 2 ) själv . hang_lamp ( "röd" , 3 ) själv . hang_lamp ( "blå" , ​​3 ) själv . hang_lamp ( "gul" , 3 ) själv . hang_lamp ( "röd" , 4 ) själv . hang_lamp ( "blå" , ​​4 ) själv . hang_lamp ( "gul" , 4 ) själv . hang_lamp ( "röd" , 5 ) själv . hang_lamp ( "blå" , ​​5 ) själv . hang_lamp ( "gul" , 5 ) själv . hang_lamp ( "röd" , 6 ) själv . hang_lamp ( "blå" , ​​6 ) själv . hang_lamp ( "gul" , 6 ) själv . hang_lamp ( "röd" , 7 ) själv . hang_lamp ( "blå" , ​​7 ) själv . hang_lamp ( "gul" , 7 ) def hang_lamp ( själv , färg , branch_number ): själv . get_branch ( gren_nummer ) . hänga ( LampFactory . get_lamp ( färg )) själv . lamps_hung += 1 if __name__ == '__main__' : ChristmasTree () . klä_upp_trädet ()

Python-exempel (med konstruktoröverstyrning)

Python-källkod (med konstruktoröverstyrning) klass Lampa ( objekt ): __instanser = dict () def __new__ ( cls , färg ): returnera cls . __instanser . setdefault ( färg , super () . __new__ ( cls )) def __init__ ( själv , färg ): själv . färg = färg klass TreeBranch ( objekt ): def __init__ ( self , branch_number ): self . branch_number = branch_number def hang ( själv , lampa ): print ( f "Häng $ { lamp . color } [$ { id ( lamp ) } ] lampa på gren $ { self . branch_number } [$ { id ( self ) } ]" ) klass Julgran ( objekt ): def __init__ ( själv ): själv . lamps_hung = 0 själv . grenar = {} def get_branch ( själv , nummer ): returnera själv . grenar . setdefault ( nummer , TreeBranch ( nummer )) def dress_up_the_tree ( self ): för gren i intervallet ( 1 , 8 ): för färg i "rött" , "blått" , "gult" : själv . hang_lamp ( färg , gren ) def hang_lamp ( själv , färg , branch_number ): själv . get_branch ( gren_nummer ) . hänga ( Lampa ( färg )) själv . lamps_hung += 1 if __name__ == '__main__' : ChristmasTree () . klä_upp_trädet ()

Exempel #1 i Java

Java-källa importera java.util.* ; public enum FontEffect { BOLD , KURSIV , SUPERSCRIPT , SUBSCRIPT , STRIKETHROUGH } public final class FontData { /** * En svag hashkarta kommer att tappa oanvända referenser till FontData. * Värden måste lindas in i WeakReferences, * eftersom värdeobjekt i svag hashkarta hålls av starka referenser. */ private static final WeakHashMap < FontData , WeakReference < FontData >> flyweightData = new WeakHashMap < FontData , WeakReference < FontData >> (); privat final int pointSize ; privat slutlig String fontFace ; privat slutlig Färg färg ; private final Set < FontEffect > effekter ; privat FontData ( int pointSize , String fontFace , Color color , EnumSet < FontEffect > effects ) { this . pointSize = pointSize ; detta . fontFace = fontFace ; detta . färg = färg ; detta . effekter = Samlingar . unmodifiableSet ( effekter ); } public static FontData create ( int pointSize , String fontFace , Color color , FontEffect ... effekter ) { EnumSet < FontEffect > effectsSet = EnumSet . noneOf ( FontEffect . class ); effekterSet . addAll ( Arrays . asList ( effekter )); // Vi bryr oss inte om kostnaden för att skapa objekt, vi minskar den totala minnesförbrukningen FontData data = new FontData ( pointSize , fontFace , color , effectsSet ); if ( ! flyweightData . containsKey ( data )) { flyweightData . put ( data , new WeakReference < FontData > ( data )); } // returnera den enda oföränderliga kopian med de givna värdena return flyweightData . ( data ). (); } @Override public boolean equals ( Object obj ) { if ( obj instanceof FontData ) { if ( obj == this ) { return true ; } FontData other = ( FontData ) obj ; returnera andra . pointSize == pointSize && annat . fontFace . lika med ( fontFace ) && annat . färg . är lika med ( färg ) && annat . effekter . lika med ( effekter ); } returnera falskt ; } @Åsidosätt public int hashCode () { return ( pointSize * 37 + effekter . hashCode ( ) * 13 ) * fontFace . hashCode (); } // Getters för teckensnittsdata, men inga sättare. FontData är oföränderligt. }

Exempel #2 i Java

Java-källa offentlig abstrakt klass _ _ skyddad char- symbol ; skyddad int bredd ; skyddad int höjd ; public abstract void printCharacter (); } public class CharacterA utökar EnglishCharacter { public CharacterA (){ symbol = 'A' ; bredd = 10 ; höjd = 20 ; } @Override public void printCharacter () { System . ut . println ( "Symbol = " + symbol + " Bredd = " + bredd + " Höjd = " + höjd ); } } public class CharacterB utökar EnglishCharacter { public CharacterB (){ symbol = 'B' ; bredd = 20 ; höjd = 30 ; } @Override public void printCharacter () { System . ut . println ( "Symbol = " + symbol + " Bredd = " + bredd + " Höjd = " + höjd ); } } public class CharacterC utökar EnglishCharacter { public CharacterC (){ symbol = 'C' ; bredd = 40 ; höjd = 50 ; } @Override public void printCharacter () { System . ut . println ( "Symbol = " + symbol + " Bredd = " + bredd + " Höjd = " + höjd ); } } offentlig klass FlyweightFactory { privat HashMap < Integer , EnglishCharacter > characters = new HashMap (); public EnglishCharacter getCharacter ( int characterCode ){ EnglishCharacter character = characters . get ( teckenkod ); if ( tecken == null ){ switch ( characterCode ){ case 1 : { character = new CharacterA (); bryta ; } fall 2 : { character = new CharacterB (); bryta ; } fall 3 : { character = new CharacterC (); bryta ; } } tecken . put ( teckenkod , tecken ); } returtecken ; _ } } /* * En klass som visar hur flugviktsdesignmönstret fungerar. * */ public class Application { public static void main ( String [] args ){ FlyweightFactory factory = new FlyweightFactory (); int [] characterCodes = { 1 , 2 , 3 }; for ( int nextCode : characterCodes ){ EnglishCharacter character = factory . getCharacter ( nextCode ); karaktär . printCharacter (); } } }

Exempel i C#

Källtext i C# använder System ; använder System.Collections ; namnutrymme Flugvikt { class MainApp { static void Main () { // Bygg ett dokument med textsträngdokument = " AAZZBBZB" ; char [] chars = dokument . ToCharArray (); CharacterFactory f = ny CharacterFactory (); // yttre tillstånd int pointSize = 10 ; // För varje karaktär använd ett flugviktsobjekt föreach ( char c in chars ) { pointSize ++; Tecken tecken = f . GetCharacter ( c ); karaktär . Display ( pointSize ); } // Vänta på användarkonsolen . läs (); } } // "FlyweightFactory" class CharacterFactory { privata hashtabelltecken = ny hashtabell ( ); public Character GetCharacter ( char key ) { // Använder "lat initialisering" Character character = characters [ key ] som Character ; if ( tecken == null ) { switch ( nyckel ) { case 'A' : character = new CharacterA (); bryta ; case 'B' : character = new CharacterB (); bryta ; //... case 'Z' : character = new CharacterZ (); bryta ; } tecken . Lägg till ( nyckel , tecken ); } returtecken ; _ } } // "flugvikt" abstrakt klass Character { skyddad char - symbol ; skyddad int bredd ; skyddad int höjd ; skyddad int uppstigning ; skyddad int nedstiga ; skyddad int pointSize ; public virtual void Display ( int pointSize ) { this . pointSize = pointSize ; Konsol . WriteLine ( denna . symbol + " (pointsize " + this . pointSize + ")" ); } } // "ConcreteFlyweight" class CharacterA : Character { // Constructor public CharacterA () { this . symbol = 'A' ; detta . höjd = 100 ; detta . bredd = 120 ; detta . stiga = 70 ; detta . nedstigning = 0 ; } } // "ConcreteFlyweight" class CharacterB : Character { // Constructor public CharacterB () { this . symbol = 'B' ; detta . höjd = 100 ; detta . bredd = 140 ; detta . stiga = 72 ; detta . nedstigning = 0 ; } } // ... C, D, E, etc. // "ConcreteFlyweight" class CharacterZ : Character { // Constructor public CharacterZ () { this . symbol = 'Z' ; detta . höjd = 100 ; detta . bredd = 100 ; detta . stiga = 68 ; detta . nedstigning = 0 ; } } }

C++ exempel

Källtext i C++ #inkludera <karta> #include <iostream> #inkludera <minne> // "Flyweight" klass Karaktär { offentliga : virtuell ~ Character () = default ; virtuell void display () const = 0 ; skyddad : röding mSymbol ; int mWidth ; int mHöjd ; int mAscent ; int mDescent ; int mPointSize ; }; // "ConcreteFlyweight" -klass ConcreteCharacter : offentlig karaktär { offentliga : // Constructor ConcreteCharacter ( char aSymbol , int aPointSize ) { mSymbol = aSymbol ; mBred = 120 ; mHöjd = 100 ; mAscent = 70 ; mDescent = 0 ; mPointSize = aPointSize ; } // från tecken virtuell void display () const { std :: cout << mSymbol << " ( PointSize " << mPointSize << " ) \n " ; } }; // "FlyweightFactory" mall < const int POINT_SIZE > klass CharacterFactory { offentliga : const Character & getCharacter ( char aKey ) { // Använder "lat initialisering" -tecken :: const_iterator it = mCharacters . hitta ( aKey ); if ( mCharacters . end () == it ) { mCharacters [ aKey ] = std :: make_unique < const ConcreteCharacter > ( aKey , POINT_SIZE ); return * mCharacters [ aKey ]; } annat { returnera * it -> sekund ; } } privat : använder Characters = std :: map < char , std :: unique_ptr < const Character > > ; Tecken mTecken ; }; int main (){ std :: stringdocument = " AAZZBBZB " ; CharacterFactory < 12 > characterFactory ; för ( auto it : document ){ auto && character = characterFactory . getCharacter ( it ); karaktär . visa (); } returnera 0 ; }

PHP5 exempel

PHP källkod <?php // "FlyweightFactory" -klassen CharacterFactory { private $characters = array (); public function GetCharacter ( $key ) { // Använder "lat initialisering" om ( ! array_key_exists ( $key , $this -> characters )) { switch ( $key ) { case 'A' : $this -> characters [ $key ] = nytt teckenA (); bryta ; case 'B' : $this -> tecken [ $key ] = nytt teckenB (); bryta ; //... case 'Z' : $this -> characters [ $key ] = new CharacterZ (); bryta ; } } returnera $this -> tecken [ $key ]; } } // "Flyweight" abstrakt klass Character { protected $symbol ; skyddad $bredd ; skyddad $höjd ; skyddad $uppstigning ; skyddad $nedstigning ; skyddad $pointSize ; offentlig abstrakt funktion Display ( $pointSize ); } // "ConcreteFlyweight" class CharacterA extends Character { // Konstruktörens offentliga funktion __construct () { $this -> symbol = 'A' ; $this -> höjd = 100 ; $this -> width = 120 ; $this -> stigning = 70 ; $this -> descent = 0 ; } public function Display ( $pointSize ) { $this -> pointSize = $pointSize ; print ( $this -> symbol . " (pointsize " . $this -> pointSize . ")" ); } } // "ConcreteFlyweight" class CharacterB extends Character { // Konstruktörens offentliga funktion __construct () { $this -> symbol = 'B' ; $this -> höjd = 100 ; $this -> width = 140 ; $this -> stigning = 72 ; $this -> descent = 0 ; } public function Display ( $pointSize ) { $this -> pointSize = $pointSize ; print ( $this -> symbol . " (pointsize " . $this -> pointSize . ")" ); } } // ... C, D, E, etc. // "ConcreteFlyweight" class CharacterZ utökar Character { // Konstruktörens offentliga funktion __construct () { $this -> symbol = 'Z' ; $this -> höjd = 100 ; $this -> width = 100 ; $this -> stigning = 68 ; $this -> descent = 0 ; } public function Display ( $pointSize ) { $this -> pointSize = $pointSize ; print ( $this -> symbol . " (pointsize " . $this -> pointSize . ")" ); } } $document = "AAZZBBZB" ; // Bygg ett dokument med texten $chars = str_split ( $document ); print_r ( $chars ); $f = new CharacterFactory (); // yttre tillstånd $pointSize = 0 ; // För varje karaktär använd ett flugviktsobjekt föreach ( $chars som $key ) { $pointSize ++ ; $character = $f -> GetCharacter ( $key ); $character -> Display ( $pointSize ); } ?>

VB.NET exempel

Källkod i VB.NET Importer System. Collections Namnutrymme flugvikt Klassprogram Shared Sub Main ( ) ' Bygg ett dokument med text Dim document As String = "AAZZBBZB" Dim chars As Char () = dokument . ToCharArray () Dim f As New CharacterFactory () ' yttre tillstånd Dim pointSize Som heltal = 10 ' För varje karaktär använd ett flugviktsobjekt För varje c Som Char In chars pointSize += 1 Dim tecken Som Character = f . GetCharacter ( c ) tecken . Visa ( pointSize ) Nästa " Vänta på användarkonsolen . Läs () End Sub End Class ' "FlyweightFactory" Klass CharacterFactory Privata karaktärer som ny hashtabell () Offentlig funktion GetCharacter ( ByVal- tangent Som Character ) As Character ' Använder "lat initialisering" Dim tecken Som Character = TryCast ( tecken ( key ), Character ) Om tecknet är ingenting Välj Skiftlägesknapp Skiftläge " A " c tecken = Nytt teckenA () Exit Välj Case "B"c tecken = Ny CharacterB () Exit Välj '... Case "Z"c character = New CharacterZ () Avsluta Välj Avsluta Välj tecken . Lägg till ( nyckel , tecken ) End If Returtecken End Function End Class ' "Flyweight" MustInherit Klass Teckenskyddad symbol Som tecken Skyddad bredd Som heltal Skyddad höjd Som heltal Skyddad uppstigning Som heltal Skyddad nedstigning Som heltal Skyddad punktStorlek Som heltal Public MustOverride Sub Display ( ByVal pointSize As Integer ) Slutklass _ ' "ConcreteFlyweight" Class CharacterA ärver Character ' Constructor Public Sub New () Me . symbol = "A" c Me . höjd = 100 Me . bredd = 120 Me . stigning = 70 Me . nedstigning = 0 End Sub Public Overrides Sub Display ( ByVal pointSize As Integer ) Me . pointSize = pointSize Console . WriteLine ( Me . symbol & " (pointsize " & Me . pointSize & ")" ) End Sub End Class ' "ConcreteFlyweight" Class CharacterB ärver karaktär ' Constructor Public Sub New () Me . symbol = "B" c Me . höjd = 100 Me . bredd = 140 Me . uppstigning = 72 Jag . nedstigning = 0 End Sub Public Overrides Sub Display ( ByVal pointSize As Integer ) Me . pointSize = pointSize Console . WriteLine ( Me . symbol & " (pointsize " & Me . pointSize & ")" ) End Sub slutklass _ ' ... C, D, E, etc. ' "ConcreteFlyweight" Class CharacterZ ärver karaktär ' Constructor Public Sub New () Me . symbol = "Z" c Me . höjd = 100 Me . bredd = 100 Me . uppstigning = 68 Jag . nedstigning = 0 End Sub Public Overrides Sub Display ( ByVal pointSize As Integer ) Me . pointSize = pointSize Console . WriteLine ( Me . symbol & " (pointsize " & Me . pointSize & ")" ) End Sub End Class End Namespace

Ruby exempel

Ruby källkod # Facility objektklass Lamp attr_reader : color #attr_reader gör färgattribut tillgängligt utanför #klassen genom att anropa .color på en lampinstans def initiera ( färg ) @ färg = slut på färg class TreeBranch def initialize ( branch_number ) @branch_number = branch_number end def hang ( lampa ) sätter "Häng #{ lamp . color } lamp on branch #{ @branch_number } " end end # Flugvikt Fabriksklass LampFactory def initialisera @lamps = { } slut def find_lamp ( färg ) om @lamps . has_key? ( färg ) # om lampan redan finns, referera till den istället för att skapa en ny lampa = @lampor [ color ] else lamp = Lamp . ny ( färg ) @lamps [ färg ] = lampände lampände _ _ def total_number_of_lamps_made @lamps . storlek ändände _ class ChristmasTree def initialize @lamp_factory = LampFactory . nya @lamps_hung = 0 klä_upp_trädslutet _ def hang_lamp ( färg , branch_number ) TreeBranch . ny ( grennummer ) . hänga ( @lamp_factory . find_lamp ( color )) @lamps_hung += 1 ände 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 ( 'röd' , 3 ) hang_lamp ( 'blå' , 3 ) hang_lamp ( 'gul' , 3 ) hang_lamp ( 'röd' , 4 ) hang_lamp ( 'blå' , 4 ) hang_lamp ( 'gul' , 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 ) slutar med "Made #{ @lamp_factory . total_number_of_lamps_made } total lamps " end

Symboler i Smalltalk

Karaktärer i Smalltalk är nästan identiska med "vanliga strängar" men regenereras inte varje gång. Två identiska tecken är faktiskt alltid samma instans av klassen Symbol, medan två identiska strängar kan vara olika instanser av klassen String.

Länkar