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 .
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 );
}
?>
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
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