TechnologyZer
technologyzer.com

Flyweight design pattern

Flyweight design pattern is a software design pattern that aims to minimize memory usage and improve performance by sharing common data across multiple objects. It achieves this by separating intrinsic (shared) and extrinsic (unique) data, allowing objects to share common data and reducing the overall memory footprint. This pattern is particularly useful in situations where a large number of similar objects need to be created, as it helps to conserve memory and optimize resource utilization.

When to use flyweight design Pattern:

  1. Application has a large number of similar objects that can share common state.
  2. The shared state can be extrinsic (unique), intrinsic (shared), or a combination of both.
  3. The cost of creating and maintaining individual objects is high, and memory consumption needs to be minimized.
  4. You want to improve performance by reducing memory usage and enhancing cache utilization.

Intrinsic data refers to the properties or characteristics of an object that are shared among multiple instances of that object.
Extrinsic data refers to the unique properties or context-specific information associated with individual instances of an object.

How to convert a code to Flyweight design pattern:

  1. Identify the intrinsic and extrinsic state of the object and separate it out.
  2. Create a flyweight interface or abstract class:
    • Define methods to manipulate the extrinsic state of flyweight objects.
  3. Implement concrete flyweight classes:
    • Implement the flyweight interface or extend the abstract class to create concrete flyweight objects.
    • Store and manage shared intrinsic state within flyweight objects.
  4. Create a flyweight factory:
    • Implement a factory class responsible for creating and managing flyweight objects.
    • Use a data structure (e.g., map) to cache and retrieve flyweight objects based on intrinsic state.
    • Only add getters of intrinsic values. Do not add any setter.
  5. Modify client code to use flyweight objects:
    • Replace direct creation of objects with calls to the flyweight factory to obtain shared flyweight objects.
    • Set extrinsic state as needed for each instance.

Example without Flyweight Design Pattern:

Example with Flyweight Design Pattern:

// Book class representing a book in the library
class Book {
private String isbn; // Intrinsic value
private String title; // Intrinsic value
private String borrowerName; // Extrinsic value
private String borrowingDate; // Extrinsic value
private String returnDate; // Extrinsic value

public Book(String isbn, String title) {
this.isbn = isbn;
this.title = title;
}

// Getters and setters for extrinsic values
public String getBorrowerName() {
return borrowerName;
}

public void setBorrowerName(String borrowerName) {
this.borrowerName = borrowerName;
}

public String getBorrowingDate() {
return borrowingDate;
}

public void setBorrowingDate(String borrowingDate) {
this.borrowingDate = borrowingDate;
}

public String getReturnDate() {
return returnDate;
}

public void setReturnDate(String returnDate) {
this.returnDate = returnDate;
}
}

// Library class managing books
class Library {
private List<Book> books = new ArrayList<>();

// Method to add a new book to the library
public void addBook(String isbn, String title) {
books.add(new Book(isbn, title));
}

// Getter for books
public List<Book> getBooks() {
return books;
}
}

// Client code
public class LibrarySystem {
public static void main(String[] args) {
Library library = new Library();

// Adding books to the library
library.addBook("1234567890", "Introduction to Java Programming");
library.addBook("0987654321", "Design Patterns: Elements of Reusable Object-Oriented Software");

// Assuming we need to store extrinsic information for each book
for (Book book : library.getBooks()) {
book.setBorrowerName("John Doe");
book.setBorrowingDate("2024-04-10");
book.setReturnDate("2024-04-17");
}
}
}
// Flyweight interface for books
interface Book {
    void borrow(String borrowerName, String borrowingDate, String returnDate);
}

// Concrete book class implementing Book interface
class ConcreteBook implements Book {
    private String isbn; // Intrinsic value
    private String title; // Intrinsic value

    public ConcreteBook(String isbn, String title) {
        this.isbn = isbn;
        this.title = title;
    }

 //only getters of intrinsic values. No setter available.

    @Override
    public void borrow(String borrowerName, String borrowingDate, String returnDate) {
        System.out.println("Book ISBN: " + isbn + ", Title: " + title + ", Borrower: " + borrowerName +
                ", Borrowing Date: " + borrowingDate + ", Return Date: " + returnDate);
    }
}

class BookFactory {
    private static final Map<String, Book> bookCache = new HashMap<>();

    public static Book getBook(String isbn, String title) {
        String key = isbn + "_" + title;
        Book book = null;
        if (bookCache.containsKey(key)) {
            return bookCache.get(key);
        }
        else{
            book = new ConcreteBook(isbn, title);
            bookCache.put(key, book);
        }
        return book;
    }
}

// Library class managing books
class Library {
    private List<Book> books = new ArrayList<>();

    // Method to add a new book to the library
    public void addBook(String isbn, String title) {
        books.add(BookFactory.getBook(isbn, title));
    }

    // Getter for books
    public List<Book> getBooks() {
        return books;
    }
}

// Client code
public class LibrarySystem {
    public static void main(String[] args) {
        Library library = new Library();

        // Adding books to the library
        library.addBook("1234567890", "Introduction to Java Programming");
        library.addBook("0987654321", "Design Patterns: Elements of Reusable Object-Oriented Software");

        // Borrowing books from the library
        for (Book book : library.getBooks()) {
            book.borrow("John Doe", "2024-04-10", "2024-04-17");
        }
    }
}

Leave a Comment