Muchá váha (designový vzor)

Aktuální verze stránky ještě nebyla zkontrolována zkušenými přispěvateli a může se výrazně lišit od verze recenzované 4. července 2016; kontroly vyžadují 23 úprav .
oportunista
Muší váha
Typ strukturální
Popsáno v Návrhové vzory Ano

Muchá váha ( angl.  flyweight , “lightweight (element)”) je strukturní návrhový vzor, ​​ve kterém objekt, který se prezentuje jako jedinečná instance na různých místech v programu, ve skutečnosti není.

Účel

Optimalizace paměti zabráněním vytváření instancí prvků, které mají společnou entitu.

Popis

Muchá váha se používá ke snížení nákladů při manipulaci s velkým množstvím malých předmětů. Při návrhu Flyweight je nutné rozdělit její vlastnosti na vnější a vnitřní. Vnitřní vlastnosti se vždy nemění, zatímco vnější vlastnosti se mohou lišit v závislosti na místě a kontextu aplikace a musí být přesunuty mimo montéra.

Flyweight doplňuje šablonu Factory Method tak, že když klient zavolá Factory Method k vytvoření nového objektu, hledá již vytvořený objekt se stejnými parametry, jako má požadovaný, a vrací jej klientovi. Pokud takový objekt neexistuje, továrna vytvoří nový.

Příklady

Příklad Pythonu

Zdrojový kód v Pythonu class Lampa ( objekt ): def __init__ ( self , barva ): self . barva = barva třída LampFactory : lampy = diktát () @staticmethod def get_lamp ( barva ): return LampFactory . lampy . setdefault ( color , Lamp ( color )) třída TreeBranch ( objekt ): def __init__ ( self , číslo_ větve ): self . číslo_pobočky = číslo_pobočky def hang ( self , lampa ): print ( f "Hang $ { lamp . color } [$ { id ( lamp ) } ] lamp on branch $ { self . branch_number } [$ { id ( self ) } ]" ) class ChristmasTree ( object ): def __init__ ( self ): self . lamps_hung = 0 self . větve = {} def get_branch ( self , number ): return self . větví . setdefault ( číslo , větev stromu ( číslo )) def dress_up_the_tree ( self ): self . hang_lamp ( "červená" , 1 ) self . hang_lamp ( "modrá" , ​​1 ) self . hang_lamp ( "žlutá" , 1 ) self . hang_lamp ( "červená" , 2 ) self . hang_lamp ( "modrá" , 2 ) self . hang_lamp ( "žlutá" , 2 ) self . hang_lamp ( "červená" , 3 ) self . hang_lamp ( "modrá" , 3 ) ​​self . hang_lamp ( "žlutá" , 3 ) self . hang_lamp ( "červená" , 4 ) self . hang_lamp ( "modrá" , 4 ) self . hang_lamp ( "žlutá" , 4 ) self . hang_lamp ( "červená" , 5 ) self . hang_lamp ( "modrá" , 5 ) self . hang_lamp ( "žlutá" , 5 ) self . hang_lamp ( "červená" , 6 ) self . hang_lamp ( "modrá" , ​​6 ) self . hang_lamp ( "žlutá" , 6 ) self . hang_lamp ( "červená" , 7 ) self . hang_lamp ( "modrá" , ​​7 ) self . hang_lamp ( "žlutá" , 7 ) def hang_lamp ( self , color , branch_number ): self . get_branch ( číslo_větve ) . zavěsit ( LampFactory . get_lamp ( barva )) self . lampy_zavěšené += 1 if __name__ == '__main__' : Vánoční strom () . dress_up_the_tree ()

Příklad Pythonu (s přepsáním konstruktoru)

Zdrojový kód Pythonu (s přepsáním konstruktoru) třída Lampa ( objekt ): __instance = dict () def __new__ ( cls , barva ): return cls . __případy . setdefault ( color , super () . __new__ ( cls )) def __init__ ( self , barva ): self . barva = barva třída TreeBranch ( objekt ): def __init__ ( self , číslo_ větve ): self . číslo_pobočky = číslo_pobočky def hang ( self , lampa ): print ( f "Hang $ { lamp . color } [$ { id ( lamp ) } ] lamp on branch $ { self . branch_number } [$ { id ( self ) } ]" ) class ChristmasTree ( object ): def __init__ ( self ): self . lamps_hung = 0 self . větve = {} def get_branch ( self , number ): return self . větví . setdefault ( číslo , větev stromu ( číslo )) def dress_up_the_tree ( self ): pro větev v rozsahu ( 1 , 8 ): pro barvu v „červené“ , „modré“ , ​​„žluté“ : self . hang_lamp ( barva , větev ) def hang_lamp ( self , color , branch_number ): self . get_branch ( číslo_větve ) . pověsit ( Lampa ( barva )) vlastní . lampy_zavěšené += 1 if __name__ == '__main__' : Vánoční strom () . dress_up_the_tree ()

Příklad č. 1 v Javě

Zdroj Java import java.util.* ; public enum FontEffect { TUČNÉ , ITALIC , SUPERSCRIPT , SUBSCRIPT , STRIKETHROUGH } public final class FontData { /** * Slabá hashová mapa zahodí nepoužívané odkazy na FontData. * Hodnoty musí být zabaleny do WeakReferences, * protože hodnotové objekty ve slabé hash mapě jsou drženy silnými referencemi. */ private static final WeakHashMap < FontData , WeakReference < FontData >> flyweightData = new WeakHashMap < FontData , WeakReference < FontData >> (); private final int pointSize ; private final String fontFace ; soukromé finální Barva barva ; private final Set < FontEffect > efekty ; private FontData ( int pointSize , String fontFace , Barva barvy , EnumSet < FontEffect > efekty ) { this . pointSize = pointSize ; toto . fontFace = fontFace ; toto . barva = barva ; toto . efekty = Kolekce . unmodifiableSet ( efekty ); } public static FontData create ( int pointSize , String fontFace , Barva barvy , FontEffect ... efekty ) { EnumSet < FontEffect > effectsSet = EnumSet . noneOf ( FontEffect . class ); sada efektů . addAll ( Arrays . asList ( effects )); // Náklady na vytvoření objektu nás nezajímají, snižujeme celkovou spotřebu paměti Data FontData = new FontData ( pointSize , fontFace , color , effectsSet ); if ( ! flyweightData . obsahujeKey ( data )) { flyweightData . put ( data , new WeakReference < FontData > ( data )); } // vrátí jedinou neměnnou kopii s danými hodnotami return flyweightData . získat ( data ). získat (); } @Override public boolean rovná se ( Objekt obj ) { if ( obj instanceof FontData ) { if ( obj == toto ) { return true ; } FontData other = ( FontData ) obj ; vrátit jiné . pointSize == pointSize && další . fontFace . rovná se ( fontFace ) && další . barva . rovná se ( barva ) && jiné . účinky . rovná se ( účinky ); } return false ; } @Override public int hashCode () { return ( pointSize * 37 + efekty . hashCode () * 13 ) * fontFace . hashCode (); } // Gettry pro data písem, ale žádné nastavovače. FontData jsou neměnná. }

Příklad č. 2 v Javě

Zdroj Java veřejná abstraktní třída _ _ chráněný znakový symbol ; chráněná int šířka ; chráněná int výška ; public abstract void printCharacter (); } public class CharacterA extends EnglishCharacter { public CharacterA (){ symbol = 'A' ; šířka = 10 ; výška = 20 ; } @Override public void printCharacter () { System . ven . println ( "Symbol = " + symbol + " Šířka = " + šířka + " Výška = " + výška ); } } public class CharacterB extends EnglishCharacter { public CharacterB (){ symbol = 'B' ; šířka = 20 ; výška = 30 ; } @Override public void printCharacter () { System . ven . println ( "Symbol = " + symbol + " Šířka = " + šířka + " Výška = " + výška ); } } public class CharacterC extends EnglishCharacter { public CharacterC (){ symbol = 'C' ; šířka = 40 ; výška = 50 ; } @Override public void printCharacter () { System . ven . println ( "Symbol = " + symbol + " Šířka = " + šířka + " Výška = " + výška ); } } public class FlyweightFactory { private HashMap < Integer , EnglishCharacter > znaky = new HashMap (); public EnglishCharacter getCharacter ( int characterCode ){ EnglishCharacter character = characters . získat ( kód znaku ); if ( znak == null ){ switch ( kód znaku ){ případ 1 : { znak = nový znakA (); zlomit ; } case 2 : { znak = new CharacterB (); zlomit ; } case 3 : { znak = new CharacterC (); zlomit ; } } znaků . vložit ( znakKód , znak ); } návratový znak ; } } /* * Třída, která ukazuje, jak funguje návrhový vzor Flyweight. * */ public class Aplikace { public static void main ( String [] args ){ Factory FlyweightFactory = new FlyweightFactory (); int [] kódy znaků = { 1 , 2 , 3 }; for ( int nextCode : characterCodes ){ EnglishCharacter character = factory . getCharacter ( nextCode ); charakter . vytisknoutZnak (); } } }

Příklad v C#

Zdrojový text v C# pomocí System ; pomocí System.Collections ; jmenný prostor Flyweight { class MainApp { static void Main () { // Sestavení dokumentu s textovým řetězcem document = "AAZZBBZB" ; char [] chars = dokument . ToCharArray (); CharacterFactory f = new CharacterFactory (); // vnější stav int pointSize = 10 ; // Pro každý znak použijte objekt typu flyweight foreach ( char c in chars ) { pointSize ++; Charakter znaku = f . GetCharacter ( c ); charakter . Display ( pointSize ); } // Počkejte na uživatelskou konzoli . číst (); } } // "FlyweightFactory" class CharacterFactory { private Hashtable characters = new Hashtable (); public Character GetCharacter ( char key ) { // Používá "línou inicializaci" Character character = characters [ key ] jako Character ; if ( znak == null ) { switch ( klíč ) { case 'A' : znak = new CharacterA (); zlomit ; případ 'B' : znak = nový znakB (); zlomit ; //... case 'Z' : znak = new CharacterZ (); zlomit ; } znaků . Přidat ( klíč , znak ); } návratový znak ; } } // "muší váha" abstract class Character { protected char symbol ; chráněná int šířka ; chráněná int výška ; chráněný int výstup ; chráněný int sestup ; protected int pointSize ; public virtual void Display ( int pointSize ) { this . pointSize = pointSize ; Konzole . WriteLine ( this . symbol + " (pointsize " + this . pointSize + ")" ); } } // "ConcreteFlyweight" class CharacterA : Character { // Konstruktor public CharacterA () { this . symbol = 'A' ; toto . výška = 100 ; toto . šířka = 120 ; toto . stoupat = 70 ; toto . sestup = 0 ; } } // "ConcreteFlyweight" class CharacterB : Character { // Konstruktor public CharacterB () { this . symbol = 'B' ; toto . výška = 100 ; toto . šířka = 140 ; toto . stoupat = 72 ; toto . sestup = 0 ; } } // ... C, D, E atd. // "ConcreteFlyweight" class CharacterZ : Character { // Konstruktor public CharacterZ () { this . symbol = 'Z' ; toto . výška = 100 ; toto . šířka = 100 ; toto . stoupat = 68 ; toto . sestup = 0 ; } } }

Příklad C++

Zdrojový text v C++ #include <mapa> #include <iostream> #include <paměť> // Třída "muší váha" Character { veřejnost : virtuální ~ Znak () = výchozí ; virtuální void zobrazení () const = 0 ; chráněno : char mSymbol ; int mWidth ; int mVýška ; int mAscent ; int mSestup ; int mPointSize ; }; // Třída "ConcreteFlyweight" ConcreteCharacter : public Character { veřejnost : // Konstruktor ConcreteCharacter ( char aSymbol , int aPointSize ) { mSymbol = aSymbol ; mWidth = 120 ; mVýška = 100 ; mAscent = 70 ; mSestup = 0 ; mPointSize = aPointSize ; } // z virtuálního zobrazení znaku void () const { std :: cout << mSymbol << " ( Velikost bodu " << Velikost mPointu << " ) \n " ; } }; // Šablona "FlyweightFactory" < const int POINT_SIZE > třída CharacterFactory { veřejnost : const Character & getCharacter ( char aKey ) { // Používá "línou inicializaci" Characters :: const_iterator it = mCharacters . najít ( aKey ); if ( mCharacters . end () == it ) { mCharacters [ aKey ] = std :: make_unique < const ConcreteCharacter > ( aKey , POINT_SIZE ); return * mCharacters [ aKey ]; } jinak { return * it -> sekunda ; } } soukromé : using Characters = std :: map < char , std :: unique_ptr < const Character > > ; Postavy mPostavy ; }; int main (){ std :: stringdocument = " AAZZBBZB " ; CharacterFactory < 12 > characterFactory ; for ( auto it : document ){ auto && znak = characterFactory . getCharacter ( it ); charakter . zobrazit (); } návrat 0 ; }

Příklad PHP5

Zdrojový kód PHP <?php // "FlyweightFactory" class CharacterFactory { private $characters = array (); public function GetCharacter ( $key ) { // Používá "línou inicializaci" if ( ! array_key_exists ( $key , $this -> znaky )) { switch ( $key ) { case 'A' : $this -> znaky [ $klíč ] = nový znakA (); zlomit ; case 'B' : $this -> znaky [ $key ] = new CharacterB (); zlomit ; //... case 'Z' : $this -> znaky [ $klíč ] = new CharacterZ (); zlomit ; } } return $this -> znaky [ $klíč ]; } } // "Muší váha" abstract class Character { protected $symbol ; chráněná $šířka ; chráněná $výška ; chráněný $výstup ; chráněný $sestup ; chráněný $pointSize ; veřejná abstraktní funkce Display ( $pointSize ); } // "ConcreteFlyweight" class CharacterA extends Character { // Konstruktor public function __construct () { $this -> symbol = 'A' ; $this -> výška = 100 ; $toto -> šířka = 120 ; $this -> vzestup = 70 ; $this -> sestup = 0 ; } public function Display ( $pointSize ) { $this -> pointSize = $pointSize ; tisknout ( $this -> symbol . " (velikost bodu " . $this -> velikost bodu . ")" ); } } // "ConcreteFlyweight" class CharacterB extends Character { // Konstruktor public function __construct () { $this -> symbol = 'B' ; $this -> výška = 100 ; $toto -> šířka = 140 ; $toto -> stoupání = 72 ; $this -> sestup = 0 ; } public function Display ( $pointSize ) { $this -> pointSize = $pointSize ; tisknout ( $this -> symbol . " (velikost bodu " . $this -> velikost bodu . ")" ); } } // ... C, D, E atd. // "ConcreteFlyweight" class CharacterZ extends Character { // Konstruktor public function __construct () { $this -> symbol = 'Z' ; $this -> výška = 100 ; $toto -> šířka = 100 ; $this -> stoupání = 68 ; $this -> sestup = 0 ; } public function Display ( $pointSize ) { $this -> pointSize = $pointSize ; tisknout ( $this -> symbol . " (velikost bodu " . $this -> velikost bodu . ")" ); } } $document = "AAZZBBZB" ; // Sestavení dokumentu s textem $chars = str_split ( $document ); print_r ( $chars ); $f = new CharacterFactory (); // vnější stav $pointSize = 0 ; // Pro každý znak použijte objekt flyweight foreach ( $chars as $key ) { $pointSize ++ ; $znak = $f -> GetCharacter ( $klíč ); $znak -> Zobrazení ( $pointSize ); } ?>

Příklad VB.NET

Zdrojový kód ve VB.NET Import System.Collections Jmenný prostor Flyweight Třída Program Shared Sub Main () ' Sestavení dokumentu s textem Dim document As String = "AAZZBBZB" Dim chars As Char () = document . ToCharArray () Dim f jako nový CharacterFactory () ' vnější stav Dim pointSize As Integer = 10 ' Pro každý znak použijte objekt typu flyweight Pro každý c As Char In chars pointSize += 1 Dim character As Character = f . GetCharacter ( c ) znak . Display ( pointSize ) Další ' Počkejte na uživatelskou konzoli . Číst () End Sub End Class ' Třída "FlyweightFactory" CharacterFactory Soukromé postavy jako nový hashtable () Veřejná funkce GetCharacter ( ByVal key As Char ) As Character ' Používá "línou inicializaci" Dim character As Character = TryCast ( znaky ( klávesa ), Character ) If character Is Nothing Then Select Case " A"c character = New CharacterA ( ) Konec Vybrat velikost písmen "B"c znak = Nový znakB () Konec Vybrat '... Velká písmena "Z"c znak = Nový znakZ () Konec Vybrat Konec Vybrat znaky . Přidat ( klíč , znak ) End If Return znak End Function End Class ' "Flyweight" MustInherit Class Character Chráněný symbol As Char Chráněná šířka As Integer Chráněná výška As Integer Chráněný vzestup As Integer Chráněný sestup Jako Integer Chráněný bodVelikost As Integer Public MustOverride Sub Display ( ByVal pointSize As Integer ) End Class ' Třída "ConcreteFlyweight" CharacterA zdědí charakter ' Constructor Public Sub New () Me . symbol = "A" c Me . výška = 100 Me . šířka = 120 Me . stoupání = 70 Me . sestup = 0 End Sub Public Overrides Sub Display ( ByVal pointSize As Integer ) Me . pointSize = pointSize konzola . WriteLine ( Me . symbol & " (pointsize " & Me . pointSize & ")" ) End Sub End Class ' Třída "ConcreteFlyweight" CharacterB zdědí charakter ' Constructor Public Sub New () Me . symbol = "B" c Me . výška = 100 Me . šířka = 140 Me . stoupání = 72 Me . sestup = 0 End Sub Public Overrides Sub Display ( ByVal pointSize As Integer ) Me . pointSize = pointSize konzola . WriteLine ( Me . symbol & " (pointsize " & Me . pointSize & ")" ) End Sub závěrečná třída ' ... C, D, E atd. ' Třída "ConcreteFlyweight" CharacterZ Dědí charakter ' Constructor Public Sub New () Me . symbol = "Z" c Me . výška = 100 Me . šířka = 100 Me . stoupání = 68 Me . sestup = 0 End Sub Public Overrides Sub Display ( ByVal pointSize As Integer ) Me . pointSize = pointSize konzola . WriteLine ( Me . symbol & " (pointsize " & Me . pointSize & ")" ) End Sub End Class End Namespace

Ruby příklad

Zdrojový kód Ruby # Třída objektu zařízení Lamp attr_reader :color #attr_reader zpřístupňuje atribut color mimo tuto třídu voláním .color na instanci Lamp def initialize ( color ) @color = color end end class TreeBranch def initialize ( číslo_větve ) @číslo_větve = číslo_větve konec def hang ( lampa ) umístí "Hang #{ lampa . color } lampa na větev #{ @branch_number } " end end # Flyweight Factory class LampFactory def initialize @lamps = {} end def find_lamp ( color ) if @lamps . has_key? ( barva ) # pokud lampa již existuje, použijte ji namísto vytvoření nové lampy = @lamps [ barva ] else lamp = Lamp . new ( color ) @lamps [ color ] = konec lampy konec lampy def total_number_of_lamps_made @lamps . velikost konec konec class ChristmasTree def initialize @lamp_factory = LampFactory . new @lamps_hung = 0 dress_up_the_tree end def hang_lamp ( barva , číslo_větve ) TreeBranch . nové ( číslo_pobočky ) . zavěsit ( @lamp_factory . find_lamp ( color )) @lamps_hung += 1 konec def dress_up_the_tree hang_lamp ( 'červená' , 1 ) hang_lamp ( 'modrá' , 1 ) hang_lamp ( 'žlutá' , 1 ) hang_lamp ( 'červená' , 2 ) hang_lamp ( 'modrá' , 2 ) hangy_lamp ( ' modrá' , 2 ) hangy_lamp hang_lamp ( 'červená' , 3 ) hang_lamp ( 'modrá' , 3 ) hang_lamp ( 'žlutá' , 3 ) hang_lamp ( 'červená' , 4 ) hang_lamp ( 'modrá' , 4 ) hang_lamp ( 'žlutá ) ( ' žlutá ) ' 'red' , 5 ) hang_lamp ( 'modrá' , 5 ) hang_lamp ( 'žlutá' , 5 ) hang_lamp ( 'červená' , 6 ) hang_lamp ( 'modrá' , 6 ) hang_lamp ( 'žlutá' , 6 ) hang_lamp ( ' žlutá' , 6 )' zavěšená ' , 7 ) hang_lamp ( 'modrá' , 7 ) hang_lamp ( 'yellow' , 7 ) vloží "Made #{ @lamp_factory . total_number_of_lamps_made } total lamps" end end

Symboly ve Smalltalku

Postavy ve Smalltalku jsou téměř totožné s „obyčejnými strunami“, ale pokaždé se neregenerují. Dva stejné znaky jsou ve skutečnosti vždy stejnou instancí třídy Symbol, zatímco dva stejné řetězce mohou být různými instancemi třídy String.

Odkazy