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