Greutatea muștei (model de design)
Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de
versiunea revizuită la 4 iulie 2016; verificările necesită
23 de modificări .
Un flyweight ( eng. flyweight , „lightweight (element)”) este un model de proiectare structurală în care un obiect care se prezintă ca o instanță unică în diferite locuri din program, de fapt, nu este.
Scop
Optimizarea memoriei prin prevenirea creării de instanțe ale elementelor care au o entitate comună.
Descriere
Flyweight este folosit pentru a reduce costurile atunci când aveți de-a face cu un număr mare de obiecte mici. Atunci când proiectați un Flyweight, este necesar să-i împărțiți proprietățile în externe și interne. Proprietățile interne rămân întotdeauna neschimbate, în timp ce proprietățile externe pot diferi în funcție de locul și contextul de aplicare și trebuie mutate în afara instalatorului.
Flyweight completează șablonul Factory Method în așa fel încât atunci când un client apelează o Factory Method pentru a crea un nou obiect, caută un obiect deja creat cu aceiași parametri ca și cel necesar și îl returnează clientului. Dacă nu există un astfel de obiect, fabrica va crea unul nou.
Exemple
Exemplu Python
Cod sursă în Python
clasă Lampă ( obiect ):
def __init__ ( self , color ):
self . culoare = culoare
clasă LampFactory :
lămpi = dict ()
@staticmethod
def get_lamp ( culoare ):
return LampFactory . lămpi . setdefault ( culoare , Lampă ( culoare ))
clasa TreeBranch ( obiect ):
def __init__ ( self , branch_number ):
self . ramură_număr = ramură_număr
def hang ( self , lamp ):
print ( f "Hang $ { lamp . color } [$ { id ( lamp ) } ] lamp on branch $ { self . branch_number } [$ { id ( self ) } ]" )
clasa Pomul de Crăciun ( obiect ):
def __init__ ( self ):
self . lamps_hung = 0
self . ramuri = {}
def get_branch ( self , number ):
return self . ramuri . setdefault ( număr , TreeBranch ( număr ))
def dress_up_the_tree ( self ):
sine . hang_lamp ( "roșu" , 1 )
self . hang_lamp ( „albastru” , 1 )
sine . hang_lamp ( "galben" , 1 )
self . hang_lamp ( "roșu" , 2 )
self . hang_lamp ( „albastru” , 2 )
sine . hang_lamp ( "galben" , 2 )
self . hang_lamp ( "roșu" , 3 )
self . hang_lamp ( „albastru” , 3 )
sine . hang_lamp ( "galben" , 3 )
self . hang_lamp ( "roșu" , 4 )
self . hang_lamp ( „albastru” , 4 )
sine . hang_lamp ( "galben" , 4 )
self . hang_lamp ( "roșu" , 5 )
self . hang_lamp ( "albastru" , 5 )
sine . hang_lamp ( "galben" , 5 )
self . hang_lamp ( "roșu" , 6 )
self . hang_lamp ( „albastru” , 6 )
sine . hang_lamp ( "galben" , 6 )
self . hang_lamp ( "roșu" , 7 )
self . hang_lamp ( "albastru" , 7 )
sine . hang_lamp ( "galben" , 7 )
def hang_lamp ( self , color , branch_number ):
self . obține_ramură ( număr_ramură ) . hang ( LampFactory . get_lamp ( culoare ))
sine . lămpi_atârnate += 1
if __name__ == '__main__' : Pomul de
Crăciun () . îmbracă_copacul ()
Exemplu Python (cu anularea constructorului)
Cod sursă Python (cu înlocuirea constructorului)
clasă Lampă ( obiect ):
__instances = dict ()
def __new__ ( cls , culoare ):
return cls . __instanțe . setdefault ( culoare , super () . __new__ ( cls ))
def __init__ ( self , color ):
self . culoare = culoare
clasa TreeBranch ( obiect ):
def __init__ ( self , branch_number ):
self . ramură_număr = ramură_număr
def hang ( self , lamp ):
print ( f "Hang $ { lamp . color } [$ { id ( lamp ) } ] lamp on branch $ { self . branch_number } [$ { id ( self ) } ]" )
clasa Pomul de Crăciun ( obiect ):
def __init__ ( self ):
self . lamps_hung = 0
self . ramuri = {}
def get_branch ( self , number ):
return self . ramuri . setdefault ( număr , TreeBranch ( număr ))
def dress_up_the_tree ( self ):
pentru ramura din interval ( 1 , 8 ):
pentru culoare în „roșu” , „albastru” , ”galben” :
sine . hang_lamp ( culoare , ramură )
def hang_lamp ( self , color , branch_number ):
self . obține_ramură ( număr_ramură ) . atârnă ( Lampă ( culoare ))
sine . lămpi_atârnate += 1
if __name__ == '__main__' : Pomul de
Crăciun () . îmbracă_copacul ()
Exemplul #1 în Java
Sursa Java
import java.util.* ;
public enum FontEffect {
BOLD , ITALIC , SUPERSCRIPT , SUBSCRIPT , STRIKETHROUGH
}
public final class FontData {
/**
* O hartă hash slabă va elimina referințele neutilizate la FontData.
* Valorile trebuie să fie împachetate în WeakReferences,
* deoarece obiectele de valoare din harta hash slabă sunt deținute de referințe puternice.
*/
private static final WeakHashMap < FontData , WeakReference < FontData >> flyweightData =
new WeakHashMap < FontData , WeakReference < FontData >> ();
private final int pointSize ;
private final String fontFace ;
culoare finală privată ; _ Private final Set < FontEffect > efecte ;
private FontData ( int pointSize , String fontFace , Color color , EnumSet < FontEffect > efecte ) {
aceasta . pointSize = pointSize ;
aceasta . fontFace = fontFace ;
aceasta . culoare = culoare ;
aceasta . efecte = Colecții . unmodiableSet ( efecte );
}
public static FontData create ( int pointSize , String fontFace , Color color ,
FontEffect ... efecte ) {
EnumSet < FontEffect > effectsSet = EnumSet . noneOf ( FontEffect . class );
set de efecte . addAll ( Arrays . asList ( efecte ));
// Nu suntem preocupați de costul de creare a obiectelor, reducem consumul total de memorie
FontData data = new FontData ( pointSize , fontFace , color , effectsSet );
if ( ! flyweightData . containsKey ( data )) {
flyweightData . put ( date , nou WeakReference < FontData > ( date ));
}
// returnează singura copie imuabilă cu valorile date
return flyweightData . obține ( date ). obține ();
}
@Override
public boolean equals ( Object obj ) {
if ( obj instanceof FontData ) {
if ( obj == this ) {
return true ;
}
FontData other = ( FontData ) obj ;
returnează altele . pointSize == pointSize && altele . fontFace . este egal cu ( fontFace )
&& altele . culoare . egal ( culoare ) && altele . efecte . egal ( efecte );
}
return false ;
}
@Override
public int hashCode () {
return ( pointSize * 37 + efecte . hashCode () * 13 ) * fontFace . hashCode ();
}
// Getters pentru datele fontului, dar nu setters. FontData este imuabil.
}
Exemplul #2 în Java
Sursa Java
clasa public abstract _ _
simbol char protejat ;
protected int width ;
protected int inaltime ;
public abstract void printCharacter ();
}
Clasa publică CharacterA extinde limba englezăCharacter {
Public CharacterA (){
simbol = 'A' ;
latime = 10 ;
inaltime = 20 ;
}
@Override
public void printCharacter () {
System . afară . println ( "Simbol = " + simbol + " Latime = " + latime + " Inaltime = " + inaltime );
}
}
Clasa publică Caracterul B extinde caracterul englezesc {
public CharacterB (){
simbol = 'B' ;
latime = 20 ;
inaltime = 30 ;
}
@Override
public void printCharacter () {
System . afară . println ( "Simbol = " + simbol + " Latime = " + latime + " Inaltime = " + inaltime );
}
}
Clasa publică CharacterC extinde EnglishCharacter {
public CharacterC (){
simbol = 'C' ;
latime = 40 ;
inaltime = 50 ;
}
@Override
public void printCharacter () {
System . afară . println ( "Simbol = " + simbol + " Latime = " + latime + " Inaltime = " + inaltime );
}
}
clasă publică FlyweightFactory {
private HashMap < Integer , EnglishCharacter > caractere = new HashMap ();
public EnglishCharacter getCharacter ( int characterCode ){
EnglishCharacter caracter = caractere . get ( caracterCod );
if ( caracter == null ){
comutare ( caracterCod ){
cazul 1 : {
caracter = caracter nouA ( ); rupe ; } cazul 2 : { caracter = caracter nou B (); rupe ; } cazul 3 : { caracter = new CharacterC (); rupe ; } } caractere . put ( caracterCod , caracter ); } caracter de returnare ; }
}
/*
* O clasă care arată cum funcționează modelul de design Flyweight.
* */
Aplicație de clasă publică {
public static void main ( String [] args ){
FlyweightFactory factory = new FlyweightFactory ();
int [] characterCodes = { 1 , 2 , 3 };
for ( int nextCode : characterCodes ){
EnglishCharacter character = factory . getCharacter ( nextCode );
caracter . printCharacter ();
}
}
}
Exemplu în C#
Text sursă în C#
folosind System ;
folosind System.Collections ;
spatiu de nume Flyweight
{
class MainApp
{
static void Main ()
{
// Construiește un document cu
șir de text document = "AAZZBBZB" ;
char [] chars = document . ToCharArray ();
CharacterFactory f = new CharacterFactory ();
// stare extrinsecă
int pointSize = 10 ;
// Pentru fiecare caracter folosiți un obiect cu greutatea muștei
foreach ( char c in chars )
{
pointSize ++;
Caracter caracter = f . GetCharacter ( c );
caracter . Display ( pointSize );
}
// Așteptați
Consola utilizatorului . citește ();
}
}
// „FlyweightFactory”
class CharacterFactory
{
private Hashtable characters = new Hashtable ();
public Character GetCharacter ( cheie caracter ) { // Folosește „inițializarea leneșă” Caracter caracter = caractere [ cheie ] ca caracter ; if ( caracter == null ) { comutator ( tasta ) { case 'A' : caracter = caracter nou A (); rupe ; case 'B' : caracter = caracter nou B (); rupe ; //... case 'Z' : caracter = new CharacterZ (); rupe ; } caractere . Adăugați ( cheie , caracter ); } caracter de returnare ; } }
// "greutatea musca"
abstract class Character
{
protected char symbol ;
protected int width ;
protected int inaltime ;
protejat int urcare ;
protected int descend ;
protected int pointSize ;
public virtual void Display ( int pointSize )
{
this . pointSize = pointSize ;
Consola . WriteLine ( acest simbol . + " (dimensiunea punctului " + acest .pointSize + " ) " ); } }
// „ConcreteFlyweight”
class CharacterA : Character
{
// Constructor
public CharacterA ()
{
this . simbol = 'A' ;
aceasta . inaltime = 100 ;
aceasta . latime = 120 ;
aceasta . urcare = 70 ;
aceasta . coborâre = 0 ;
}
}
// „ConcreteFlyweight”
class CharacterB : Character
{
// Constructor
public CharacterB ()
{
this . simbol = 'B' ;
aceasta . inaltime = 100 ;
aceasta . latime = 140 ;
aceasta . urcare = 72 ;
aceasta . coborâre = 0 ;
}
}
// ... C, D, E etc.
// „ConcreteFlyweight”
class CharacterZ : Character
{
// Constructor
public CharacterZ ()
{
this . simbol = 'Z' ;
aceasta . inaltime = 100 ;
aceasta . latime = 100 ;
aceasta . urcare = 68 ;
aceasta . coborâre = 0 ;
}
}
}
Exemplu C++
Text sursă în C++
#include <hartă>
#include <iostream>
#include <memorie>
// Clasa „Flyweight” Caracter
{
public :
virtual ~ Caracter () = implicit ;
virtual void display () const = 0 ;
protejat :
char mSymbol ;
int mWidth ;
int mHeight ;
int mAscent ;
int mDescent ;
int mPointSize ;
};
// Clasa "ConcreteFlyweight" ConcreteCharacter : caracter public
{
public :
// Constructor
ConcreteCharacter ( char aSymbol , int aPointSize )
{
mSymbol = aSimbol ;
mWidth = 120 ;
m Înălțime = 100 ;
mAscent = 70 ;
mCoborâre = 0 ;
mPointSize = aPointSize ;
}
// din caracterul
virtual void display () const {
std :: cout << mSymbol << " ( PointSize " << mPointSize << " ) \n " ;
}
};
// Șablon „FlyweightFactory” < const int POINT_SIZE >
clasa CharacterFactory
{
public :
const Character & getCharacter ( char aKey )
{
// Folosește "inițializarea leneșă"
Caractere :: const_iterator it = mCaractere . găsi ( aKey );
if ( mCaractere . end () == it ) {
mCaractere [ aKey ] = std :: make_unique < const ConcreteCharacter > ( aKey , POINT_SIZE );
returnează * mCaractere [ aKey ];
} altfel {
return * it -> secunda ;
}
}
privat :
folosind Caractere = std :: map < char , std :: unique_ptr < const Character > > ;
Caractere mCaractere ;
};
int main (){
std :: stringdocument = " AAZZBBZB " ;
CharacterFactory < 12 > characterFactory ;
pentru ( auto it : document ){
auto && caracter = characterFactory . getCharacter ( it );
caracter . afișaj ();
}
returnează 0 ;
}
Exemplu PHP5
Cod sursă PHP
<?php
// Clasa "FlyweightFactory" CharacterFactory
{
private $caractere = matrice ();
funcția publică GetCharacter ( $key ) { // Folosește „inițializarea leneșă” dacă ( ! array_key_exists ( $key , $this -> caractere )) { switch ( $key ) { case 'A' : $this -> caractere [ $key ] = caracter nouA ( ); rupe ; case 'B' : $this -> caractere [ $key ] = new CharacterB (); rupe ; //... case 'Z' : $acest -> caractere [ $key ] = new CharacterZ (); rupe ; } } returnează $this -> caractere [ $key ]; } }
// Clasa abstractă „Flyweight” Caracter { protected $simbol ; protejat $width ; protected $height ; protejat $ascensiunea ; protejat $descent ; protejat $pointSize ;
funcția abstractă publică Display ( $pointSize ); }
// „ConcreteFlyweight”
class CharacterA extins Character
{
// Constructor
public function __construct ()
{
$this -> simbol = 'A' ;
$this -> inaltime = 100 ;
$this -> latime = 120 ;
$this -> urcare = 70 ;
$aceasta -> coborâre = 0 ;
}
funcția publică Display ( $pointSize )
{
$this -> pointSize = $punctSize ;
print ( $this -> simbol . " (pointsize " . $this -> pointSize . ")" );
}
}
// „ConcreteFlyweight”
class CharacterB extinde Caracterul
{
// Constructor
public function __construct ()
{
$this -> simbol = 'B' ;
$this -> inaltime = 100 ;
$this -> latime = 140 ;
$this -> urcare = 72 ;
$aceasta -> coborâre = 0 ;
}
funcția publică Display ( $pointSize )
{
$this -> pointSize = $punctSize ;
print ( $this -> simbol . " (pointsize " . $this -> pointSize . ")" );
}
}
// ... C, D, E etc.
// „ConcreteFlyweight”
class CharacterZ extinde Character
{
// Constructor
public function __construct ()
{
$this -> simbol = 'Z' ;
$this -> inaltime = 100 ;
$this -> latime = 100 ;
$this -> urcare = 68 ;
$aceasta -> coborâre = 0 ;
}
funcția publică Display ( $pointSize )
{
$this -> pointSize = $punctSize ;
print ( $this -> simbol . " (pointsize " . $this -> pointSize . ")" );
}
}
$document = "AAZZBBZB" ;
// Construiește un document cu text
$cars = str_split ( $document );
print_r ( $caractere );
$f = new CharacterFactory ();
// stare extrinsecă
$pointSize = 0 ;
// Pentru fiecare personaj folosiți un obiect cu greutatea muștei
foreach ( $caracterele ca $key ) {
$pointSize ++ ;
$caracter = $f -> GetCharacter ( $cheie );
$caracter -> Afișare ( $pointSize );
}
?>
Cod sursă în VB.NET
Sistem de importuri.Colectii
Spațiu de nume Flyweight
Class Program
Shared Sub Main ()
' Creați un document cu text
Dim document As String = "AAZZBBZB"
Dim chars As Char () = document . ToCharArray ()
Dim f ca nou CharacterFactory ()
' stare extrinsecă
Dim pointSize As Integer = 10
' Pentru fiecare personaj utilizați un obiect cu greutatea muștei
Pentru fiecare c As Char În caractere
pointSize += 1
Dim character As Character = f . GetCharacter ( c )
caracter . Afișează ( pointSize )
În continuare
' Așteptați
Consola utilizator . Citiți ()
End Sub
End Class
Clasa „FlyweightFactory” CharacterFactory Caractere
private ca noua tabelă hash ()
Funcție publică GetCharacter ( Tasta ByVal As Character ) As Character ' Folosește „inițializarea leneșă” caracterul Dim As Character = TryCast ( caractere ( tasta ), Character ) Dacă caracterul nu este nimic , atunci Selectați Tasta majuscule și majuscule Caracterul „ A ”c = Caracter nouA () Ieșire Selectare Caracter "B"c = Caracter nou B () Ieșire Selectare '... Caracter " Z" c = Caracter nouZ ( ) Ieșire Selectare Sfârșit Selectare caractere . Adăugați ( cheie , caracter ) End If Returnează caracterul End Function End Class
' "Flyweight"
MustInherit Clasa Caracter
Simbol protejat Ca Char Lățimea protejată Ca întreg Înălțimea protejată Ca întreg Urcarea protejată Ca întreg Coborârea protejată Ca întreg Punctul protejat Dimensiunea Ca întreg
Public MustOverride Sub Display ( ByVal pointSize As Integer )
Clasa finală
' "ConcreteFlyweight"
Clasa CaracterulA
moștenește caracterul
' Constructor
Public Sub Nou ()
Eu . simbol = "A" c
Eu . inaltime = 100
Me . latime = 120
Me . urcare = 70
Me . descent = 0
End Sub
Public Overscrie Sub Display ( ByVal pointSize As Integer )
Eu . pointSize = pointSize
Consola . WriteLine ( Me . simbol & " (pointsize " & Me . pointSize & ")" )
End Sub
End Class
' "ConcreteFlyweight"
Clasa CharacterB
Moștenește caracterul
' Constructor
Public Sub Nou ()
Eu . simbol = "B" c
Me . inaltime = 100
Me . latime = 140
Me . urcare = 72
Me . descent = 0
End Sub
Public Overscrie Sub Display ( ByVal pointSize As Integer )
Eu . pointSize = pointSize
Consola . WriteLine ( Me . simbol & " (pointsize " & Eu . pointSize & ")" )
End Sub
termina clasa
' ... C, D, E etc.
' Clasa "ConcreteFlyweight" CharacterZ
Moștenește caracterul
' Constructor
Public Sub Nou ()
Eu . simbol = "Z" c
Me . inaltime = 100
Me . latime = 100
Me . urcare = 68
Me . descent = 0
End Sub
Public Overscrie Sub Display ( ByVal pointSize As Integer )
Eu . pointSize = pointSize
Consola . WriteLine ( Me . simbol & " (pointsize " & Eu . pointSize & ")" )
End Sub
End Class
End Namespace
Cod sursă Ruby
#
Clasa de obiecte facilitate Lamp
attr_reader :color
#attr_reader face ca atributul de culoare să fie disponibil în afara
clasei, apelând .color pe o instanță Lamp
def initialize ( culoare )
@color = finalul culorii
_
clasa TreeBranch
def initialize ( branch_number )
@branch_number = branch_number
end
def hang ( lampă )
pune „Hang #{ lamp . color } lamp on branch #{ @branch_number } ”
end
end
# Flyweight Factory
clasă LampFactory
def initialize
@lamps = {}
end
def find_lamp ( culoare )
dacă @lamps . are_cheie? ( culoare )
# dacă lampa există deja, referiți-o în loc să creați o
lampă nouă = @lamps [ color ]
else
lamp = Lamp . new ( culoare )
@lamps [ culoare ] = lamp
end
lamp
end
def total_number_of_lamps_made
@lamps . dimensiune
capăt
capăt
clasa ChristmasTree
def initialize
@lamp_factory = LampFactory . nou
@lamps_hung = 0
îmbracă_sfârşitul_copacului
_
def hang_lamp ( culoare , branch_number )
TreeBranch . nou ( număr_sucursală ) . hang ( @lamp_factory . find_lamp ( culoare ))
@lamps_hung += 1
capăt
def dress_up_the_tree
hang_lamp ( 'rosu' , 1 )
hang_lamp ( 'albastru' , 1 )
hang_lamp ( 'galben' , 1 )
hang_lamp ( 'rosu' , 2 )
hang_lamp ( 'albastru' , 2 )
hang_lamp ( ' , 2 ) hang_lamp (' 2 hang_lamp ( 'rosu' , 3 ) hang_lamp ( 'albastru' , 3 ) hang_lamp ( 'galben' , 3 ) hang_lamp ( 'rosu' , 4 ) hang_lamp ( 'albastru' , 4 ) hang_lamp ( 'galben' , 4 lampa ( ) 'roșu' , 5 ) hang_lamp ( 'albastru' , 5 ) hang_lamp ( 'galben' , 5 ) hang_lamp ( 'roșu' , 6 ) hang_lamp ( 'albastru' , 6 ) hang_lamp ( 'galben' , 6 ) hang_lamp ( 'rosu' ) ' , 7 ) hang_lamp ( 'albastru' , 7 ) hang_lamp ( 'yellow' , 7 ) pune "Made #{ @lamp_factory . total_number_of_lamps_made } total lamps" end end
Caracterele din Smalltalk sunt aproape identice cu „șirurile obișnuite”, dar nu sunt regenerate de fiecare dată. Două caractere identice sunt de fapt întotdeauna aceeași instanță a clasei Symbol, în timp ce două șiruri identice pot fi instanțe diferite ale clasei String.
Link -uri