Flyweight (suunnittelukuvio)

Kokeneet kirjoittajat eivät ole vielä tarkistaneet sivun nykyistä versiota, ja se voi poiketa merkittävästi 4. heinäkuuta 2016 tarkistetusta versiosta . tarkastukset vaativat 23 muokkausta .
opportunisti
Kärpässarja
Tyyppi rakenteellinen
Kuvattu suunnittelukuvioissa Joo

Perhopaino ( eng.  flyweight , "kevyt (elementti)") on rakenteellinen suunnittelumalli , jossa ohjelman eri paikoissa ainutlaatuisena esiintymänä esiintyvä kohde ei itse asiassa ole sitä.

Tarkoitus

Muistin optimointi estämällä elementtien ilmentymien luominen, joilla on yhteinen kokonaisuus.

Kuvaus

Flyweightia käytetään vähentämään kustannuksia, kun käsitellään suurta määrää pieniä esineitä. Perhopainoa suunniteltaessa on tarpeen jakaa sen ominaisuudet ulkoisiin ja sisäisiin. Sisäiset ominaisuudet pysyvät aina ennallaan, kun taas ulkoiset ominaisuudet voivat vaihdella käyttöpaikan ja -kontekstin mukaan ja ne on siirrettävä asentajan ulkopuolelle.

Flyweight täydentää Factory Method -mallia siten, että kun asiakas kutsuu Factory Methodia luodakseen uuden objektin, se etsii jo luodun objektin, jolla on samat parametrit kuin vaadittu, ja palauttaa sen asiakkaalle. Jos tällaista objektia ei ole, tehdas luo uuden.

Esimerkkejä

Python-esimerkki

Lähdekoodi Pythonissa luokka Lamppu ( objekti ): def __init__ ( itse , väri ): itse . väri = väri luokka Lampputehdas : lamput = dict () @staticmethod def get_lamp ( väri ): palauta LampFactory . lamput . asetettu oletus ( väri , lamppu ( väri )) luokka TreeBranch ( objekti ): def __init__ ( itse , haaran_numero ): itse . haaran_numero = haaran_numero def hang ( itse , lamppu ): print ( f "Hang $ { lamp . color } [$ { id ( lamp ) } ] lamp on haara $ { itse . haaran_numero } [$ { id ( itse ) } ]" ) luokka Joulupuu ( objekti ): def __init__ ( itse ): itse . lamps_hung = 0 itse . haarat = {} def get_branch ( itse , numero ): palauttaa itse . oksat . setdefault ( numero , TreeBranch ( numero )) def dress_up_the_tree ( itse ): itse . hang_lamp ( " punainen " , 1 ) itse . hang_lamp ( "sininen" , ​​1 ) itse . hang_lamp ( "keltainen" , 1 ) itse . hang_lamp ( " punainen " , 2 ) itse . hang_lamp ( "sininen" , ​​2 ) itse . hang_lamp ( "keltainen" , 2 ) itse . hang_lamp ( " punainen " , 3 ) itse . hang_lamp ( "sininen" , ​​3 ) itse . hang_lamp ( "keltainen" , 3 ) ​​itse . hang_lamp ( " punainen " , 4 ) itse . hang_lamp ( "sininen" , ​​4 ) itse . hang_lamp ( "keltainen" , 4 ) itse . hang_lamp ( " punainen " , 5 ) itse . hang_lamp ( "sininen" , ​​5 ) itse . hang_lamp ( "keltainen" , 5 ) itse . hang_lamp ( " punainen " , 6 ) itse . hang_lamp ( "sininen" , ​​6 ) itse . hang_lamp ( "keltainen" , 6 ) itse . hang_lamp ( " punainen " , 7 ) itse . hang_lamp ( "sininen" , 7 ) itse . hang_lamp ( "keltainen" , 7 ) def hang_lamp ( itse , väri , haaran_numero ): itse . get_branch ( haaran_numero ) . ripustaa ( LampFactory . get_lamp ( väri )) itse . lamput_hung += 1 if __name__ == '__main__' : Joulupuu () . pukeutua_puu ()

Python-esimerkki (konstruktorin ohituksella)

Python-lähdekoodi (konstruktorin ohituksella) luokan lamppu ( objekti ): __instances = dict () def __new__ ( cls , color ): palauttaa cls . __instanssit . setdefault ( väri , super ( ) . __new__ ( cls )) def __init__ ( itse , väri ): itse . väri = väri luokka TreeBranch ( objekti ): def __init__ ( itse , haaran_numero ): itse . haaran_numero = haaran_numero def hang ( itse , lamppu ): print ( f "Hang $ { lamp . color } [$ { id ( lamp ) } ] lamp on haara $ { itse . haaran_numero } [$ { id ( itse ) } ]" ) luokka Joulupuu ( objekti ): def __init__ ( itse ): itse . lamps_hung = 0 itse . haarat = {} def get_branch ( itse , numero ): palauttaa itse . oksat . setdefault ( numero , TreeBranch ( numero )) def dress_up_the_tree ( itse ): haaralle alueella ( 1 , 8 ) : värille " punainen " , " sininen" , "keltainen" : itse . Hang_lamp ( väri , haara ) def hang_lamp ( itse , väri , haaran_numero ): itse . get_branch ( haaran_numero ) . ripustaa ( Lamppu ( väri ) ) itse . lamput_hung += 1 if __name__ == '__main__' : Joulupuu () . pukeutua_puu ()

Esimerkki #1 Javassa

Java lähde tuonti java.util.* ; public enum FontEffect { LIHAVOI , KURSIVOINTI , SUPERSCRIPT , SUBSCRIPT , TRAKETHROUGH } julkinen loppuluokka FontData { /** * Heikko hash-kartta poistaa käyttämättömät viittaukset FontDataan . * Arvot on käärittävä WeakReferences-muotoon, * koska heikon hash-kartan arvoobjektit ovat vahvojen viittausten hallussa. */ yksityinen staattinen lopullinen WeakHashMap < FontData , WeakReference < FontData >> flyweightData = new WeakHashMap < FontData , WeakReference < FontData >> (); yksityinen lopullinen int pointSize ; yksityinen lopullinen String fontFace ; yksityinen lopullinen Väri väri ; yksityinen lopullinen Aseta < FontEffect > tehosteet ; yksityinen FontData ( int pointSize , String fontFace , Color color , EnumSet < FontEffect > Effects ) { this . pointSize = pointSize ; tämä . fontFace = fontFace ; tämä . väri = väri ; tämä . tehosteet = Kokoelmat . unmodifiableSet ( tehosteet ); } julkinen staattinen fonttitietojen luonti ( int pointSize , String fontFace , Color color , FontEffect ... tehosteet ) { EnumSet < FontEffect > EffectSet = EnumSet . noneOf ( FontEffect . class ); tehosteet . addAll ( Arrays . asList ( tehosteet )); // Emme välitä objektin luomiskustannuksista, vähennämme kokonaismuistinkulutusta FontData data = new FontData ( pointSize , fontFace , color , effectsSet ); if ( ! flyweightData . includeKey ( data )) { flyweightData . put ( data , new WeakReference < FontData > ( data )); } // palauttaa yksittäisen muuttumattoman kopion annetuilla arvoilla return flyweightData . saada ( tiedot ). saada (); } @Override public boolean on yhtä kuin ( Object obj ) { if ( obj instanceof FontData ) { if ( obj == this ) { return true ; } FontData other = ( FontData ) obj ; palauta toinen . pointSize == pointSize && other . fontFace . yhtä kuin ( fontFace ) && muu . väri . on yhtä kuin ( väri ) && muu . tehosteet . on yhtä suuri ( vaikutukset ); } return false ; } @Override public int hashCode () { return ( pointSize * 37 + tehosteet . hashCode () * 13 ) * fontFace . hashCode (); } // Fonttitietojen kerääjät, mutta ei asettajia. FontData on muuttumaton. }

Esimerkki #2 Javassa

Java lähde julkinen abstrakti luokka _ _ suojattu merkkisymboli ; _ suojattu in leveys ; suojattu sisäkorkeus ; _ julkinen abstrakti void printCharacter (); } public class CharacterA laajentaa EnglishCharacter { julkinen MerkkiA (){ symboli = 'A' ; leveys = 10 ; korkeus = 20 ; } @Override public void printCharacter () { Järjestelmä . ulos . println ( "Symboli = " + symboli + " Leveys = " + leveys + " Korkeus = " + korkeus ); } } public class CharacterB laajentaa EnglishCharacter { julkinen MerkkiB (){ symboli = 'B' ; leveys = 20 ; korkeus = 30 ; } @Override public void printCharacter () { Järjestelmä . ulos . println ( "Symboli = " + symboli + " Leveys = " + leveys + " Korkeus = " + korkeus ); } } public class CharacterC laajentaa EnglishCharacter { public CharacterC (){ symboli = 'C' ; leveys = 40 ; korkeus = 50 ; } @Override public void printCharacter () { Järjestelmä . ulos . println ( "Symboli = " + symboli + " Leveys = " + leveys + " Korkeus = " + korkeus ); } } julkinen luokka FlyweightFactory { yksityinen HashMap < Integer , EnglishCharacter > merkit = uusi HashMap (); public EnglishCharacter getCharacter ( int characterCode ){ English Character character = merkkiä . get ( characterCode ); if ( merkki == null ){ kytkin ( merkkiKoodi ){ tapaus 1 : { merkki = uusi merkkiA (); tauko ; } tapaus 2 : { merkki = uusi merkkiB (); tauko ; } tapaus 3 : { merkki = uusi merkkiC (); tauko ; } } merkkiä . laittaa ( merkkiKoodi , merkki ); } palauttaa merkki ; } } /* * Luokka, joka näyttää kuinka Flyweight-suunnittelukuvio toimii. * */ julkisen luokan hakemus { public static void main ( String [] args ){ FlyweightFactory factory = new FlyweightFactory (); int [] merkkiKoodit = { 1 , 2 , 3 }; for ( int nextCode : characterCodes ){ EnglishCharacter character = tehdas . getCharacter ( nextCode ); hahmo . tulostaCharacter (); } } }

Esimerkki C#:ssa

Lähdeteksti C# käyttäen System ; käyttämällä System.Collections -ohjelmaa ; nimiavaruus Flyweight { class MainApp { static void Main () { // Luo asiakirja, jossa on tekstimerkkijono document = " AAZZBBZB" ; char [] merkki = asiakirja . ToCharArray (); CharacterFactory f = uusi CharacterFactory (); // ulkoinen tila int pointSize = 10 ; // Käytä jokaiselle merkille flyweight-objektia foreach ( char c in chars ) { pointSize ++; Merkkimerkki = f . _ GetCharacter ( c ); hahmo . Näyttö ( pointSize ); } // Odota käyttäjän konsolia . lue (); } } // "FlyweightFactory" class CharacterFactory { yksityinen Hashtable- merkit = new Hashtable (); public Character GetCharacter ( merkkinäppäin ) { // Käyttää " laiskaa alustusta " Merkkimerkki = merkkiä [ avain ] Merkkinä ; if ( merkki == tyhjä ) { kytkin ( näppäin ) { case 'A' : merkki = uusi merkkiA (); tauko ; tapaus 'B' : merkki = uusi merkkiB (); tauko ; //... tapaus 'Z' : merkki = uusi merkkiZ (); tauko ; } merkkiä . Lisää ( avain , merkki ); } palauttaa merkki ; } } // "perhopaino" abstrakti luokka Merkki { suojattu merkkisymboli ; _ suojattu in leveys ; suojattu sisäkorkeus ; _ suojattu nousu ; _ suojattu int laskeutua ; suojattu int pointSize ; public virtual void Näyttö ( int pointSize ) { this . pointSize = pointSize ; konsoli . WriteLine ( tämä . symboli + " (pistekoko " + tämä . pointSize + ")" ); } } // "ConcreteFlyweight" class CharacterA : Merkki { // Rakentaja julkinen MerkkiA () { this . symboli = 'A' ; tämä . korkeus = 100 ; tämä . leveys = 120 ; tämä . nousu = 70 ; tämä . laskeutuminen = 0 ; } } // "ConcreteFlyweight" class MerkkiB : Merkki { // Rakentaja julkinen MerkkiB () { this . symboli = 'B' ; tämä . korkeus = 100 ; tämä . leveys = 140 ; tämä . nousu = 72 ; tämä . laskeutuminen = 0 ; } } // ... C, D, E jne. // "ConcreteFlyweight" class CharacterZ : Merkki { // Rakentaja public CharacterZ () { this . symboli = 'Z' ; tämä . korkeus = 100 ; tämä . leveys = 100 ; tämä . nousu = 68 ; tämä . laskeutuminen = 0 ; } } }

C++ esimerkki

Lähdeteksti C++:ssa #sisällytä <kartta> #include <iostream> #sisällytä <muisti> // "Flyweight" -luokka Hahmo { julkinen : virtuaalinen ~ Merkki () = oletus ; virtuaalinen tyhjänäyttö ( ) const = 0 ; suojattu : char mSymbol ; int mLeveys ; int mKorkeus ; int mascent ; int mDescent ; int mPointSize ; }; // "ConcreteFlyweight" -luokka ConcreteCharacter : julkinen hahmo { julkinen : // Rakentaja ConcreteCharacter ( char aSymbol , int aPointSize ) { mSymbol = aSymboli ; mLeveys = 120 um ; mKorkeus = 100 ; mascent = 70 °C ; mDescent = 0 ; mPointSize = aPointSize ; } // from Merkki virtuaalinen void näyttö () const { std :: cout << mSymbol << " ( PointSize " << mPointSize << " ) \n " ; } }; // "FlyweightFactory" -malli < const int POINT_SIZE > luokan CharacterFactory { julkinen : const Character & getCharacter ( char aKey ) { // Käyttää "laiskaa alustusta" Merkit :: const_iterator it = mCharacters . etsi ( aKey ); if ( mHahmot . end ( ) == se ) { mCharacters [ aKey ] = std :: make_unique < const ConcreteCharacter > ( aKey , POINT_SIZE ); return * mCharacters [ aKey ]; } muu { return * it -> second ; } } yksityinen : käyttäen Merkkejä = std :: kartta < merkki , std :: ainutlaatuinen_ptr < const Merkki > > ; Hahmot mHahmot ; }; int main (){ std :: stringdocument = " AAZZBBZB " ; CharacterFactory < 12 > characterFactory ; for ( auto it : document ){ auto && merkki = characterFactory . getCharacter ( se ); hahmo . näyttö (); } paluu 0 ; }

PHP5 esimerkki

PHP lähdekoodi <?php // "FlyweightFactory" class CharacterFactory { private $characters = array (); public function GetCharacter ( $avain ) { // Käyttää "laiskaa alustusta" if ( ! array_key_exists ( $avain , $this -> characters )) { switch ( $key ) { case 'A' : $this -> merkit [ $key ] = uusi merkkiA (); tauko ; kirjainkoko 'B' : $tämä -> merkit [ $avain ] = uusi merkkiB (); tauko ; //... tapaus 'Z' : $this -> merkit [ $key ] = uusi merkkiZ (); tauko ; } } palauttaa $this -> merkit [ $avain ]; } } // "Flyweight" abstrakti luokka Merkki { suojattu $symbol ; suojattu $width ; suojattu $korkeus ; suojattu $nousu ; suojattu $laskuminen ; suojattu $pointSize ; julkinen abstrakti funktio Näyttö ( $pointSize ); } // "ConcreteFlyweight" class MerkkiA laajentaa Merkki { // Rakentaja julkinen funktio __construct () { $this -> symbol = 'A' ; $tämä -> korkeus = 100 ; $tämä -> leveys = 120 ; $tämä -> nousu = 70 ; $tämä -> laskeutuminen = 0 ; } public function Näyttö ( $pointSize ) { $this -> pointSize = $pointSize ; print ( $this -> symbol . " (pointsize " . $this -> pointSize . ")" ); } } // "ConcreteFlyweight" class MerkkiB laajentaa Merkki { // Rakentaja julkinen funktio __construct () { $this -> symbol = 'B' ; $tämä -> korkeus = 100 ; $tämä -> leveys = 140 ; $tämä -> nousu = 72 ; $tämä -> laskeutuminen = 0 ; } public function Näyttö ( $pointSize ) { $this -> pointSize = $pointSize ; print ( $this -> symbol . " (pointsize " . $this -> pointSize . ")" ); } } // ... C, D, E jne. // "ConcreteFlyweight" class MerkkiZ laajentaa Merkki { // Rakentaja julkinen funktio __construct () { $this -> symbol = 'Z' ; $tämä -> korkeus = 100 ; $tämä -> leveys = 100 ; $tämä -> nousu = 68 ; $tämä -> laskeutuminen = 0 ; } public function Näyttö ( $pointSize ) { $this -> pointSize = $pointSize ; print ( $this -> symbol . " (pointsize " . $this -> pointSize . ")" ); } } $dokumentti = "AAZZBBZB" ; // Luo dokumentti tekstillä $chars = str_split ( $document ); print_r ( $ merkit ); $f = uusi CharacterFactory (); // ulkoinen tila $pointSize = 0 ; // Käytä jokaiselle merkille flyweight-objektia foreach ( $chars as $key ) { $pointSize ++ ; $merkki = $f -> GetCharacter ( $avain ); $merkki -> Näyttö ( $pointSize ); } ?>

VB.NET esimerkki

Lähdekoodi VB.NET:ssä Tuo System.Collections Nimiavaruus Flyweight Luokka Ohjelma Jaettu alipää () ' Rakenna asiakirja, jossa on teksti Himmeä asiakirja As String = "AAZZBBZB" Dim merkit Kuten Char ( ) = asiakirja . ToCharArray () Dim f Uusi hahmotehdas ( ) ' ulkoinen tila Dim pointSize As Integer = 10 ' Käytä kullekin merkille flyweight-objektia Jokaiselle c As Char In merkit pointSize + = 1 Dim merkki As Character = f . GetCharacter ( c ) merkki . Näyttö ( pointSize ) Seuraava Odota käyttäjäkonsolia . Lue () Lopeta Sub End Class ' "FlyweightFactory" Class CharacterFactory Yksityiset hahmot uutena hashtabletina ( ) Julkinen funktio GetCharacter ( ByVal -näppäin Merkkinä ) Merkkinä ' Käyttää "laiskaa alustusta" Himmeä merkkiä Merkkinä = TryCast ( merkit ( näppäin ), merkki ) Jos merkki ei ole mitään , valitse kirjainnäppäin Kirjainkoko " A " c merkki = Uusi merkkiA ( ) Poistu Valitse Kirjainkoko "B"c merkki = Uusi merkkiB () Poistu Valitse '... Kirjainkoko "Z"c merkki = Uusi merkkiZ () Poistu Valitse Lopeta Valitse merkit . Lisää ( näppäin , merkki ) End If Return merkki Lopeta toiminto End Class ' " Flyweight " MustInherit Class Character Suojattu symboli As Char Suojattu leveys Kokonaislukuna Suojattu korkeus Kokonaislukuna Suojattu nousu Kokonaislukuna Suojattu laskeutuminen Kokonaislukuna Suojattu pisteKoko As Integer _ Julkinen MustOverride Sub Display ( ByVal pointSize As Integer ) Loppuluokka _ ' "ConcreteFlyweight" Class CharacterA perii merkin ' Rakentaja Julkinen ala Uusi () Minä . symboli = "A" c Me . korkeus = 100 me . leveys = 120 Me . nousu = 70 Me . laskeutuminen = 0 End Sub Julkinen ohittaa alinäytön ( ByVal pointSize As Integer ) Me . _ pointSize = pointSize- konsoli . WriteLine ( Me . symboli & " ( pointsize " & Me . pointSize & " ) " ) End Sub End Class ' "ConcreteFlyweight" Class Character B perii merkin ' Rakentaja Julkinen ala Uusi () Minä . symboli = "B" c Me . korkeus = 100 me . leveys = 140 Me . nousu = 72 minä . laskeutuminen = 0 End Sub Julkinen ohittaa alinäytön ( ByVal pointSize As Integer ) Me . _ pointSize = pointSize- konsoli . WriteLine ( Me . symboli & " ( pointsize " & Me . pointSize & " ) " ) End Sub loppuluokka _ ... C, D, E jne. ' "ConcreteFlyweight" Class CharacterZ perii merkin ' Rakentaja Julkinen ala Uusi () Minä . symboli = "Z" c Me . korkeus = 100 me . leveys = 100 me . nousu = 68 Me . laskeutuminen = 0 End Sub Julkinen ohittaa alinäytön ( ByVal pointSize As Integer ) Me . _ pointSize = pointSize- konsoli . WriteLine ( Me . symboli & " ( pointsize " & Me . pointSize & " ) " ) End Sub End Class End Namespace

Rubiiniesimerkki _

Rubyn lähdekoodi # Toimitilaobjektiluokka Lamppu attr_reader : color #attr_reader tekee color attribuutista saataville #luokan ulkopuolella kutsumalla .color Lamp-instanssissa def alustaa ( väri ) @ väri = värin loppu luokka TreeBranch def alustaa ( haaran_numero ) @haaranumero = haaran_numeron loppu def hang ( lamppu ) laittaa "Hang #{ lamp . color } lamp on haara #{ @branch_number } " loppupäähän # Flyweight Factory Class LampFactory def alusta @lamps = {} end def find_lamp ( väri ) , jos @lamput . onko_avain? ( väri ) # jos lamppu on jo olemassa, viittaa siihen uuden lampun luomisen sijaan = @lamput [ väri ] else lamp = Lamppu . uusi ( väri ) @lamput [ väri ] = lampun pääty lamppu _ def_tehtyjen_lamppujen_määrä @lamput . _ koko loppupää _ luokka Joulupuu def alusta @lamp_factory = Lampputehdas . uusi @lamps_hung = 0 pukeutua_puun päähän def hang_lamp ( väri , haaran_numero ) TreeBranch . uusi ( haaran_numero ) . ripustaa ( @lamp_factory . find_lamp ( color )) @lamps_hung += 1 end def dress_up_the_tree hang_lamp ( 'punainen' , 1 ) hang_lamp ( 'sininen' , 1 ) hang_lamp ( 'keltainen' , 1 ) hang_lamp ( 'punainen' , 2 ) hang_lamp ( 'sininen' , 2 ) hang_lamp ( ' 2 keltainen ) ' hang_lamp ( 'punainen' , 3 ) hang_lamp ( 'sininen' , 3 ) hang_lamp ( 'keltainen' , 3 ) hang_lamp ( 'punainen' , 4 ) hang_lamp ( 'sininen' , 4 ) hang_lamp ( 'keltainen' , 4 ) hang_lamp ( 'keltainen', 4) punainen _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ' , 7 ) hang_lamp ( 'sininen' , 7 ) hang_lamp ( 'keltainen' , 7 ) laittaa "Valmistettu #{ @lamp_factory . total_number_of_lamps_made } total lamps" loppupäähän

Symbolit Smalltalkissa

Smalltalkin merkit ovat lähes identtisiä "tavallisten merkkijonojen" kanssa, mutta niitä ei luoda uudelleen joka kerta. Kaksi identtistä merkkiä ovat itse asiassa aina sama symboliluokan esiintymä, kun taas kaksi identtistä merkkijonoa voivat olla merkkijonoluokan eri esiintymiä.

Linkit