Hat jemand ein konkretes Beispiel für die Verwendung des Flyweight Pattern? [geschlossen]

21

Ich habe Entwurfsmuster studiert und bin über das Fliegengewichtmuster gekommen. Ich habe versucht, Möglichkeiten zur Verwendung des Musters in meinen Anwendungen zu finden, aber ich habe Probleme, die Verwendung des Musters zu erkennen. Was sind auch einige Anzeichen dafür, dass ein Fliegengewichtmuster verwendet wird, wenn ich den Code anderer Leute lese?

Nach der Definition heißt es:

Verwenden Sie die Freigabe, um eine große Anzahl feinkörniger Objekte effizient zu unterstützen.

Wenn ich es richtig lese, können Wörterbücher und Hashtables Beispiele für Fliegengewichte sein. Ist das richtig?

Danke im Voraus.

Jeremy E
quelle
7
Nur eine kleine Anekdote zu Fliegengewichten: Ich musste einmal große Excel-Dateien (bis zu 500.000 Datensätze, über 100 Spalten) mit einer Drittanbieter-API erstellen. Die Stile für die Zellen wurden extrem speicherintensiv. Wenn also ein Stil benötigt wurde, wurde eine Hash-Tabelle überprüft, ob bereits ein gleicher Stil vorhanden war, und dann nur ein Verweis auf diesen Stil bereitgestellt. Diese Änderung ermöglichte den Export. So viele Daten in Excel zu haben, ist meiner Meinung nach Wahnsinn. Aber die Controller hatten ihre Analyse-Makros, die sie behalten wollten.
Falcon
9
Kommentar: Ich hoffe, dass Leute, die Pattern- und OO-Bücher und -Artikel schreiben, in die reale Welt eines durchschnittlichen Programmierers kommen und kein Englisch im Anwaltsstil mehr verwenden!
NoChance
1
"Ich musste einmal große Excel-Dateien erstellen (bis zu 500.000 Datensätze, über 100 Spalten)" - das ist nicht viel im Vergleich zu dem, was einige Händler erstellen können ;-)
quant_dev
Nachdem ich einige dieser Beispiele gelesen habe, würde ich denken, dass die Komprimierung von Speicherdaten ein hervorragender Ort ist, um diese Technik zu implementieren. Danke für die Hilfe!
Jeremy E
Tabellenzellen in GWT sind Fliehgewichte.
user16764

Antworten:

19

Ein Beispiel sind die Java-Bibliotheken. Java hat primitive Typen (z. B. inteine 32-Bit-Ganzzahl) und Wrapper für diese (z. B. Integerwelche Wraps int). Es gibt Methoden , um „Box“ ein intin eine Integerund unbox einer Integerin ein int. Die Wrapper sind notwendig, da die primitiven Typen keine Objekte sind und daher zB nicht als Schlüssel in Maps verwendet oder in Collections platziert werden können.

Die Boxing-Methode verwendet ein Array von Flyweight-Objekten als eine Art Cache für Integers, die intWerten zwischen -128 und 127 entsprechen. Da dies die Werte sind, die am wahrscheinlichsten als Schlüssel verwendet oder in Sammlungen platziert werden, werden Zuweisung und Speicherbedarf reduziert. (Wenn 5000000 Integers den Wert 0 darstellen, wird 5000000-mal so viel Speicher belegt wie bei der Wiederverwendung der Flyweight-Instanz).

Peter Taylor
quelle
1
Der interne Pool für Zeichenfolgen in C # ist also ein weiteres Beispiel für das richtige Fliegengewichtsmuster?
Jeremy E
1
@ Jeremy E: Ja, meiner Meinung nach kann man String-Internierung als Anwendung des Flyweight-Musters bezeichnen, obwohl es sich bei Strings nicht nur um den Speicherverbrauch, sondern auch um die Laufzeiteffizienz handelt.
Falcon
Zeiger mit Objective-C-Tags bringen dies auf ein Extrem. Boxed Integer mit bis zu 56 Bit und viele Strings mit bis zu sechs Zeichen werden nicht einmal als Objekte zugewiesen, sondern alle Informationen werden in den Objektzeiger selbst gepackt.
gnasher729
9

Grafik. In der Regel ist ein Rasterbild (das das Rückgrat der meisten Computergrafiken auf Verbraucherebene ist) CPU-günstig, aber speicherintensiv (was in Ordnung ist, weil der Speicher billig, aber die CPU teuer ist). Wenn dieses Rasterbild beim Rendern einer größeren Benutzeroberfläche mehrmals wiederholt werden soll (von Symbolen in einer Windows-GUI-App über Zeichen einer Schriftart in einem Textverarbeitungsprogramm bis hin zu Texturen auf Oberflächen in einem 3D-Spiel), ist dies sehr sinnvoll Laden Sie das Bild einmal in den Speicher und zeigen Sie einfach mit sehr einfachen Objekten darauf, die billig herzustellen sind und selbst nicht viel Speicher beanspruchen. Ein Sprite, bei dem es sich lediglich um einen Punkt im Grafikbereich handelt, an dem ein Bild angezeigt werden soll, ist lediglich ein 3D-Punkt und ein Speicherzeiger auf das erste Pixel des zu verwendenden Bilds. MÖGLICHERWEISE enthält es auch die Abmessungen des zu verwendenden Teils der Sprite-Image-Datei. entweder grafisch oder speicherbezogen. Diese Informationen sind alle sehr kostengünstig zu ändern, beispielsweise um das Bild oder die Position des Sprites zu ändern, und sie können durchgeführt werden, ohne jedes Mal ein neues Bild zu laden, wodurch die Leistung des zugrunde liegenden Programms zum Manipulieren und Anzeigen der richtigen Teile des Sprites drastisch erhöht wird richtige Bilder, um eine komplette UI "Szene" zu rendern.

KeithS
quelle
3

ASCII-Range- CharacterInstanzen in Smalltalk sind Fliehgewichte.

Wenn Sie etwas wie auswerten Character space, Character class >> #value:führt Folgendes aus:

value: anInteger 
    "Answer the Character whose value is anInteger."

    anInteger > 255 ifTrue: [^self basicNew setValue: anInteger].
    ^ CharacterTable at: anInteger + 1.

Die Klassenvariable CharacterTablewird folgendermaßen initialisiert:

initialize
    "Create the table of unique Characters, and DigitsValues."
    "Character initializeClassificationTable"

    CharacterTable ifNil: [
        "Initialize only once to ensure that byte characters are unique"
        CharacterTable := Array new: 256.
        1 to: 256 do: [:i | CharacterTable
            at: i
            put: (self basicNew setValue: i - 1)]].
    self initializeDigitValues

Wenn Sie also einen String erstellen, werden die ASCII-Bereiche Characternicht CharacterTablejedes Mal neu erstellt, sondern von dort.

Frank Shearar
quelle
3

Mit dem Fliegengewichtmuster sollen unnötige Objektinitialisierungen vermieden und somit Platz gespart werden. Nach der Definition von GOF kann ein Objekt zwei Zustände haben, den intrinsischen und den extrinsischen:

  • Eigenzustand: Wird im Fliegengewicht gespeichert; Es besteht aus Informationen, die unabhängig vom Kontext der Fliehgewichte sind und somit gemeinsam genutzt werden können.
  • Extrinsischer Zustand: hängt vom Kontext des Fliegengewichts ab und variiert mit diesem und kann daher nicht geteilt werden. Client-Objekte sind dafür verantwortlich, den extrinsischen Status an das Flyweight zu übergeben, wenn es benötigt wird.

Angenommen, wir möchten eine einfache Texteditor-Anwendung entwickeln, in der jede Spalte alle Zeilen des Texts enthält und die Zeile Zeichen enthalten kann.

Das Dilemma hier ist, wie die Character-Klasse entworfen wird. Die char cinnerhalb der Character-Klasse sollte das Hauptobjekt (innerer Zustand) sein. Ein Zeichen kann jedoch eine Schriftart und eine Schriftgröße (extrinsischer Zustand) haben. Daher müssen wir seinen extrinsischen Status in der Zeile (Client) speichern und bei Bedarf darauf zugreifen. Zu diesem Zweck werden zwei Listen erstellt, in denen die Schriftarten und die Größen gespeichert sind.

Durch Befolgen des Flyweight-Musters kann das Zeichen nun wiederverwendet werden und die Objekte werden aus einer bestimmten Liste von Objekten (dem Flyweight-Pool) referenziert, die alle ASCII-Symbole ( CharacterObjekte) enthält.

Folgendes habe ich visuell beschrieben:

Bildbeschreibung hier eingeben

Zum Drucken von "Hallo" sind nur 4 Characterstatt 5 Objekte erforderlich. Sobald die Schriftart geändert wurde, sind keine neuen Objekte erforderlich. Beachten Sie, dass dies nicht möglich wäre, wenn wir den extrinsischen Status in der Character-Klasse gespeichert hätten, z.

class Character
{
    char c;
    int Size;
    Font font;

    ....
}

Das Anwenden dieses Musters auf große Datasets würde zu erheblichen Optimierungen der Speicherkomplexität der Anwendung und der Wiederverwendbarkeit von Objekten führen.

Menelaos Kotsollaris
quelle