[Design Pattern] Strukturelle Muster: Flyweight


Thomas Darimont

Premium-User
Hallo,

dieser Beitrag erklärt das Strukturelle Muster: Flyweight

Flyweights sind in der Regel welche immutable sind und so gut zwischen mehreren
Verwendern geshared werden können. Anstatt immer wieder Objekte mit der gleichen "inhaltlichen" Bedeutung
zu erzeugen, erzeugt man nur eine Instanz und referenziert dann bei der Verwendung nur noch diese.

Klassische Beispiele für Flyweights im JDK sind beispieslweise Long, Integer, Short, Byte, Character, Boolean
-> diese Wrapper-Typen verwalten intern einen Cache von Instanzen in verschiedenen Wertebereichen.
Bei Integer sind das beispielsweise die Werte von -128 bis +127. Diese gecachedten Werte kann man beispielsweise
über die Methode Integer.valueOf(64) abrufen. Der Java Compiler macht von dieser Technik (valueOf) regen gebrauch,
wenn er Autoboxing erkennt -> der Java Compiler schriebt Ausdrücke der Form Integer i = 123; um in Integer i = Integer.valueOf(123);.

Diese Cache-Size kann man übrigens auch tunen (System Property: -Djava.lang.Integer.IntegerCache.high=10000 bzw. -XX:AutoBoxCacheMax=10000)

Eine andere Stelle im JDK wo das Flyweight Pattern Anwendung findet sind Strings. String literale wie "tutorials.de" oder "ABC" werden von der JVM interned (String.intern()) -> in einen internen String-Pool aufgenommen und wiederverwendet wenn das String Literal im Code noch an anderer Stelle verwendet wird.

Hier mal ein Beispiel zur Anwendung des Flyweight Patterns:
Dabei werden wir die Name-Abstraktion mit der die Komponenten in unserem Beispiel ausgestattet sind über eine
entsprechende Factory als Flyweight realisieren.

Java:
package de.tutorials.design.patterns.structural;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.jpatterns.gof.FlyweightPattern.Flyweight;
import org.jpatterns.gof.FlyweightPattern.FlyweightFactory;

public class FlyweightExample {
  public static void main(String[] args) {
    IFactory facade = new MemoryHogFactory();
    
    System.out.println(facade.create("A")); //new name instance created A
    System.out.println(facade.create("A")); //new name instance created A
    System.out.println(facade.create("B")); //new name instance created A
    System.out.println(facade.create("B")); //new name instance created A
    
    
    System.out.println("#####");
    
    facade = new SmartFactory();
    
    System.out.println(facade.create("A")); //new name instance created
    System.out.println(facade.create("A")); //name instance A reused
    System.out.println(facade.create("B")); //new name instance created
    System.out.println(facade.create("B")); //name instance B reused
  }
  
  static interface IFactory{
    Component create(String name);
  }
  
  static class MemoryHogFactory implements IFactory{
    @Override
    public Component create(String name) {
      return new Component(new Name(name));
    }
  }
  
  @FlyweightFactory
  static class SmartFactory implements IFactory{
    
    private ConcurrentMap<String, Name> nameCache = new ConcurrentHashMap<String, Name>();
    
    @Override
    public Component create(String name) {
      Name n = nameCache.get(name);
      if(n == null){
        n = new Name(name);
        nameCache.put(name,n);
      }
      return new Component(n);
    }
  }
  
  static class Component{
    Name name;

    public Component(Name name) {
      this.name = name;
    }
    
    @Override
    public String toString() {
      return super.toString() +" name: " + name;
    }
  }
  
  
  @Flyweight
  static class Name{
    private final String value; 
    
    public Name(String value) {
      this.value = value;
    }

    public String getValue() {
      return value;
    }
    
    public String toString() {
      return super.toString() +" value: "  + value;
    }
  }
}
Ausgabe:
Code:
de.tutorials.design.patterns.structural.FlyweightExample$Component@23fc4bec name: de.tutorials.design.patterns.structural.FlyweightExample$Name@8dc8569 value: A
de.tutorials.design.patterns.structural.FlyweightExample$Component@45bab50a name: de.tutorials.design.patterns.structural.FlyweightExample$Name@64c3c749 value: A
de.tutorials.design.patterns.structural.FlyweightExample$Component@7150bd4d name: de.tutorials.design.patterns.structural.FlyweightExample$Name@6bbc4459 value: B
de.tutorials.design.patterns.structural.FlyweightExample$Component@152b6651 name: de.tutorials.design.patterns.structural.FlyweightExample$Name@544a5ab2 value: B
#####
de.tutorials.design.patterns.structural.FlyweightExample$Component@2e6e1408 name: de.tutorials.design.patterns.structural.FlyweightExample$Name@3ce53108 value: A
de.tutorials.design.patterns.structural.FlyweightExample$Component@6af62373 name: de.tutorials.design.patterns.structural.FlyweightExample$Name@3ce53108 value: A
de.tutorials.design.patterns.structural.FlyweightExample$Component@459189e1 name: de.tutorials.design.patterns.structural.FlyweightExample$Name@55f33675 value: B
de.tutorials.design.patterns.structural.FlyweightExample$Component@527c6768 name: de.tutorials.design.patterns.structural.FlyweightExample$Name@55f33675 value: B
Gruß Tom