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 .
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 . få ( data ). få ();
}
@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 );
}
?>
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 , så
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
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