Əsas məzmuna keçin

Flyweight Design Pattern

Çox sayda oxşar obyektlə işləyərkən yaddaş istifadəsini minimuma endirməyə kömək edir. Bu pattern, obyektlərin ümumi vəziyyətini paylaşaraq yaddaş səmərəliliyini artırır.

Flyweight pattern, real həyatda kitabxanaya bənzəyir. Hər oxucu üçün ayrı kitab nüsxəsi almaq əvəzinə, eyni kitabı bir çox oxucu paylaşa bilər - burada kitab flyweight, oxucunun məlumatları isə kontekstdir.

Flyweight Pattern-nin Əsas Xüsusiyyətləri

  • Memory Efficiency: Yaddaş istifadəsini minimuma endirir
  • Object Sharing: Oxşar obyektləri paylaşır
  • Intrinsic vs Extrinsic: Daxili və xarici vəziyyəti ayırır
  • Factory Management: Flyweight obyektlərini factory vasitəsilə idarə edir

Flyweight Pattern-nin Strukturu

  1. Flyweight: Paylaşılan obyektlər üçün interface
  2. ConcreteFlyweight: Flyweight interface-ni implement edən class
  3. FlyweightFactory: Flyweight obyektlərini yaradıb idarə edən factory
  4. Context: Flyweight obyektlərindən istifadə edən və xarici vəziyyəti saxlayan class

Flyweight Pattern-də Vəziyyət Növləri

  • Intrinsic State (Daxili Vəziyyət): Flyweight obyektində saxlanılan və paylaşılan vəziyyət
  • Extrinsic State (Xarici Vəziyyət): Client tərəfindən ötürülən və obyektdə saxlanmayan vəziyyət

Java-da Flyweight Pattern İmplementasiyası

Text Editor Nümunəsi

Koda bax
// Flyweight interface
interface Character {
void display(int x, int y, String color);
}

// Concrete Flyweight
class ConcreteCharacter implements Character {
private char symbol; // Intrinsic state

public ConcreteCharacter(char symbol) {
this.symbol = symbol;
}

@Override
public void display(int x, int y, String color) {
// Extrinsic state (x, y, color) is passed as parameters
System.out.println("Character '" + symbol + "' displayed at (" +
x + ", " + y + ") in " + color + " color");
}

public char getSymbol() {
return symbol;
}
}

// Flyweight Factory
class CharacterFactory {
private static java.util.Map<java.lang.Character, Character> characters =
new java.util.HashMap<>();

public static Character getCharacter(char symbol) {
Character character = characters.get(symbol);

if (character == null) {
character = new ConcreteCharacter(symbol);
characters.put(symbol, character);
System.out.println("Created new flyweight for character: " + symbol);
}

return character;
}

public static int getCreatedFlyweightsCount() {
return characters.size();
}

public static void showCreatedCharacters() {
System.out.print("Created flyweights: ");
for (Character ch : characters.keySet()) {
System.out.print(characters.entrySet().stream()
.filter(entry -> entry.getValue() == ch)
.findFirst()
.get()
.getKey() + " ");
}
System.out.println();
}
}

// Context class that uses flyweights
class TextDocument {
private java.util.List<CharacterContext> characters = new java.util.ArrayList<>();

public void addCharacter(char symbol, int x, int y, String color) {
Character character = CharacterFactory.getCharacter(symbol);
characters.add(new CharacterContext(character, x, y, color));
}

public void display() {
System.out.println("Displaying document:");
for (CharacterContext context : characters) {
context.display();
}
}

public int getTotalCharacters() {
return characters.size();
}

// Helper class to store extrinsic state
private static class CharacterContext {
private Character character;
private int x, y;
private String color;

public CharacterContext(Character character, int x, int y, String color) {
this.character = character;
this.x = x;
this.y = y;
this.color = color;
}

public void display() {
character.display(x, y, color);
}
}
}

// Client code
public class FlyweightPatternDemo {
public static void main(String[] args) {
TextDocument document = new TextDocument();

// Add characters to document
String text = "HELLO WORLD";
int x = 0, y = 0;

System.out.println("Adding characters to document...");
for (char c : text.toCharArray()) {
if (c != ' ') {
document.addCharacter(c, x, y, "Black");
}
x += 10;
}

System.out.println();
document.display();

System.out.println();
CharacterFactory.showCreatedCharacters();
System.out.println("Total characters in document: " + document.getTotalCharacters());
System.out.println("Flyweight objects created: " + CharacterFactory.getCreatedFlyweightsCount());
System.out.println("Memory saved: " +
(document.getTotalCharacters() - CharacterFactory.getCreatedFlyweightsCount()) +
" character objects");
}
}

Çıxış:

Adding characters to document...
Created new flyweight for character: H
Created new flyweight for character: E
Created new flyweight for character: L
Created new flyweight for character: O
Created new flyweight for character: W
Created new flyweight for character: R
Created new flyweight for character: D

Displaying document:
Character 'H' displayed at (0, 0) in Black color
Character 'E' displayed at (10, 0) in Black color
Character 'L' displayed at (20, 0) in Black color
Character 'L' displayed at (30, 0) in Black color
Character 'O' displayed at (40, 0) in Black color
Character 'W' displayed at (60, 0) in Black color
Character 'O' displayed at (70, 0) in Black color
Character 'R' displayed at (80, 0) in Black color
Character 'L' displayed at (90, 0) in Black color
Character 'D' displayed at (100, 0) in Black color

Created flyweights: H E L O W R D
Total characters in document: 10
Flyweight objects created: 7
Memory saved: 3 character objects

Tree Forest Nümunəsi

Koda bax
// Flyweight interface for trees
interface TreeType {
void render(int x, int y, int size, String season);
String getInfo();
}

// Concrete Flyweight
class ConcreteTreeType implements TreeType {
private String name; // Intrinsic state
private String texture; // Intrinsic state

public ConcreteTreeType(String name, String texture) {
this.name = name;
this.texture = texture;
System.out.println("Created TreeType: " + name + " with " + texture + " texture");
}

@Override
public void render(int x, int y, int size, String season) {
// Extrinsic state (x, y, size, season) passed as parameters
System.out.println("Rendering " + name + " tree at (" + x + ", " + y +
") size:" + size + " in " + season + " season");
}

@Override
public String getInfo() {
return name + " (" + texture + " texture)";
}
}

// Flyweight Factory for trees
class TreeTypeFactory {
private static java.util.Map<String, TreeType> treeTypes = new java.util.HashMap<>();

public static TreeType getTreeType(String name, String texture) {
String key = name + "_" + texture;
TreeType treeType = treeTypes.get(key);

if (treeType == null) {
treeType = new ConcreteTreeType(name, texture);
treeTypes.put(key, treeType);
}

return treeType;
}

public static int getCreatedTypesCount() {
return treeTypes.size();
}

public static void showCreatedTypes() {
System.out.println("Created tree types:");
for (TreeType type : treeTypes.values()) {
System.out.println("- " + type.getInfo());
}
}
}

// Context class for individual trees
class Tree {
private TreeType type;
private int x, y, size;
private String season;

public Tree(TreeType type, int x, int y, int size, String season) {
this.type = type;
this.x = x;
this.y = y;
this.size = size;
this.season = season;
}

public void render() {
type.render(x, y, size, season);
}
}

// Forest class that manages many trees
class Forest {
private java.util.List<Tree> trees = new java.util.ArrayList<>();

public void plantTree(String name, String texture, int x, int y, int size, String season) {
TreeType type = TreeTypeFactory.getTreeType(name, texture);
Tree tree = new Tree(type, x, y, size, season);
trees.add(tree);
}

public void renderForest() {
System.out.println("Rendering forest with " + trees.size() + " trees:");
for (Tree tree : trees) {
tree.render();
}
}

public int getTreeCount() {
return trees.size();
}
}

// Client code for forest simulation
public class ForestFlyweightDemo {
public static void main(String[] args) {
Forest forest = new Forest();

// Plant many trees of different types
System.out.println("Planting forest...");

// Plant Oak trees
forest.plantTree("Oak", "Rough", 10, 20, 15, "Spring");
forest.plantTree("Oak", "Rough", 30, 40, 12, "Summer");
forest.plantTree("Oak", "Rough", 50, 60, 18, "Autumn");

// Plant Pine trees
forest.plantTree("Pine", "Smooth", 70, 80, 20, "Winter");
forest.plantTree("Pine", "Smooth", 90, 100, 16, "Spring");

// Plant more Oak trees (reusing flyweight)
forest.plantTree("Oak", "Rough", 110, 120, 14, "Summer");
forest.plantTree("Oak", "Rough", 130, 140, 17, "Autumn");

// Plant Birch trees
forest.plantTree("Birch", "Soft", 150, 160, 10, "Spring");
forest.plantTree("Birch", "Soft", 170, 180, 11, "Summer");

System.out.println();
forest.renderForest();

System.out.println();
TreeTypeFactory.showCreatedTypes();
System.out.println("Total trees in forest: " + forest.getTreeCount());
System.out.println("Tree type flyweights created: " + TreeTypeFactory.getCreatedTypesCount());
System.out.println("Memory efficiency: " +
(forest.getTreeCount() - TreeTypeFactory.getCreatedTypesCount()) +
" object instances saved");
}
}

Flyweight Pattern-nin Üstünlükləri

  • Memory Efficiency: Yaddaş istifadəsini əhəmiyyətli dərəcədə azaldır
  • Performance: Obyekt yaratma məsrəfini azaldır
  • Scalability: Böyük sayda obyektlə işləməyə imkan verir
  • Resource Sharing: Ümumi resursları səmərəli paylaşır

Flyweight Pattern-nin Çatışmazlıqları

  • Complexity: Kodun mürəkkəbliyini artırır
  • Context Management: Xarici vəziyyətin idarə edilməsi lazımdır
  • Thread Safety: Çox thread mühitdə diqqətli olmaq lazımdır
  • Overhead: Kiçik obyektlər üçün həddən artıq ola bilər

İstifadə Halları

  • Text Editors: Mətn editorlarında simvol və şrift obyektləri
  • Game Development: Oyunlarda təkrarlanan obyektlər (mərmi, düşmən)
  • Web Browsers: HTML elementlərinin render edilməsi
  • Graphics Applications: Çoxlu primitiv forma və tekstura
  • Database Systems: Obyekt-relational mapping sistemlərində

Flyweight vs Singleton Pattern

  • Flyweight: Çox sayda oxşar obyekt üçün istifadə edilir
  • Singleton: Yalnız bir nümunə yaradılmasını təmin edir

Flyweight Pattern-in Həyata Keçirilməsi Məsləhətləri

  • Intrinsic State: Yalnız dəyişməz və paylaşıla bilən vəziyyəti flyweight-də saxlayın
  • Factory Pattern: Flyweight obyektlərini idarə etmək üçün Factory istifadə edin
  • Thread Safety: Çox thread mühitdə flyweight factory-ni thread-safe edin
  • Memory Monitoring: Yaddaş istifadəsini izləyin və nəticələri ölçün

Flyweight Pattern, böyük sayda oxşar obyektlə işləyərkən yaddaş səmərəliliyini təmin etmək üçün çox faydalı bir pattern-dir və xüsusilə performans və yaddaş optimallaşdırılması tələb olunan aplikasiyalarda geniş istifadə olunur.