6 Kasım 2018 Salı

GoF- Flyweight Örüntüsü - Immutable Nesneler İçeren Cache

Not : GoF Tasarım Örüntüleri yazısına bakabilirsiniz.

Prototype ile İlişkisi
Prototype yeni nesnelerin yarı bitmiş bir nesneden kopyalanarak yaratılması içindir. Örneğin bir oyundan EnemyPrototype ile bir çok düşman nesnesi yaratılabilir. Flyweight ise hazır nesnelerin paylaşılması içindir.

Memoization İle İlişkisi
Flyweight örüntüsü, Memoization örüntüsü ile ilişkili. Memoizaiton fonksiyon sonucunu saklarken Flyweight nesne saklar.

Factory İle İlişkisi
- Flyweight için tutulan cache bazen Factory içinde tutuluyor. Bu kullanım şeklinde Factory nesnenin yaratılması için gereken biraz daha karmaşık logic kodunu içeriyor

- Bazen de cache Flyweight nesnesinin içinde tutuluyor. Bu kullanım şeklinde nesnenin yaratılması karmaşık bir logic bulunmuyor. Örneğin Java'daki Integer.valueOf() metodu basit sayılır, dolayısıyla nesne içinde

Flyweight (Tüy Sıklet) Yapısal Örüntü
Bu örüntüde bazı nesneler önceden yaratılır ve tekrar tekrar kullanılır. Nesneler paylaşıldığı için immutable olması gerekir. Açıklaması şöyle
- The Flyweight pattern is used to minimize the memory usage by sharing as much data as possible with other similar objects.
- The Flyweight pattern provides a way to reduce the number of objects created and to decrease memory footprint and increase performance.
- The Flyweight pattern tries to reuse already existing similar kind objects by storing them in a collection which act like a cache and creates new object when no matching object is found.
- The Flyweight objects we create as immutable. This means that they cannot be modified once they have been constructed. Making flyweight objects as immutable helps while sharing them with other objects. 
Immutable Nesnelerin Doğası
Açıklaması şöyle. Intrinsic (içsel) veri değişmemeli. Extrinsic (dışsal) veri değişebilir ve flyweight içinde tutulmamalı 
The Flyweight object essentially has two different kind of attributes – 
- Intrinsic - An intrinsic (invariant) state attribute is stored and shared in the flyweight object. It is independent of flyweight’s context. So, as the best practice we should make intrinsic states immutable.

- Extrinsic - An extrinsic (variant) state attribute does not store and share in the flyweight object because it depends on flyweight’s context and varies as context change. Generally, we store and maintain the extrinsic state in the Client objects. We need to pass this extrinsic state to the flyweight object for object creation and processing.
Ekran Listeleri
Flyweight ekranda listelenen static nesneler için güzel bir kullanım şekli olabilir.

ObjectPool gibi düşünmek
Bazıları nesneler tekrar tekrar kullanıldığı için ObjectPool'un özelleşmiş bir hali olarak düşünüyorlar.

En çok bilinen örneklerinden birisi Java'daki Integer önbelleğidir. Ayrıca grafik kütüphanelerinde de bu örüntü sıkça görülebilir. Aşağıdaki şekilde bu örüntü görülebilir.

Flyweight Pattern Implementation - UML Class Diagram
Örnek
Şöyle yaparız. Burada Factory ve Flyweight birlikte kullanılıyor
public class ShapeFactory {

  private static final Map circleMap = new HashMap<>();

  public static Shape getShape(String Color) {
    Circle circle = (Circle) circleMap.get(Color);
    if (circle != null) {
      return circle;
    } else {
      circle = new Circle(Color);
      circleMap.put(Color, circle);
    }
    return circle;
  }
}

Tehlikeler
Eğer cache'e dışarıdan müdahale olursa kodda çok acaip hatalar olabilir
Örnek
Bu kod parçasında FlighWeight örüntüsü yüzünden 2+2 = 5 yapılması gösteriliyor.
import java.lang.reflect.Field;

public class Main {
  public static void main(String[] args) throws Exception {
    Class cache = Integer.class.getDeclaredClasses()[0];
    Field c = cache.getDeclaredField("cache");
    c.setAccessible(true);
    Integer[] array = (Integer[]) c.get(cache);
    array[132] = array[133];

    System.out.printf("%d",2 + 2);
  }
}

Hiç yorum yok:

Yorum Gönder