Core Principles of Flyweight Pattern
The Flyweight Pattern is a structural design pattern that minimizes memory usage by sharing reusable objects. This approach optimizes performance for resource-intensive objects, similar to pooling techniques like database connection pools or string interning.
Key Characteristics
Flyweight objects distinguish between two states:
- Intrinsic state: Immutable, shared data initialized via constructor
- Extrinsic state: Context-dependent, mutable properties
Implementation Components
A typical Flyweight implementation includes:
- Flyweight interface defining common operations
- Concrete flyweight implementing shared logic
- Factory managing object reuse through a caching mechanism
Practical Example: Flight Information System
Flight interfaec definition:
public interface FlightTicket {
void displayStatus();
}
Concrete flight implementation:
public class AirlineTicket implements FlightTicket {
private final String flightNumber;
private final String origin;
private final String destination;
private boolean delayed;
public AirlineTicket(String number, String from, String to) {
flightNumber = number;
origin = from;
destination = to;
delayed = Math.random() > 0.5;
}
@Override
public void displayStatus() {
System.out.printf("Flight %s from %s to %s: %s%n",
flightNumber, origin, destination,
delayed ? "Delayed" : "On Time");
}
}
Factory with caching mechanism:
import java.util.HashMap;
import java.util.Map;
public class TicketFactory {
private static Map<String, FlightTicket> cache = new HashMap<>();
public static FlightTicket getTicket(String number, String from, String to) {
String key = number + "_" + from + "_" + to;
FlightTicket ticket = cache.get(key);
if (ticket == null) {
System.out.println("Creating new ticket instance");
ticket = new AirlineTicket(number, from, to);
cache.put(key, ticket);
} else {
System.out.println("Using cached ticket");
}
return ticket;
}
}
Real-World Application: Integer Caching
Java's Integer class demonstrates Flyweight principles through value caching:
public class IntegerCacheDemo {
public static void main(String[] args) {
// Cache hit (-128 to 127)
Integer a = Integer.valueOf(100);
Integer b = Integer.valueOf(100);
System.out.println(a == b); // true
// Cache miss
Integer c = Integer.valueOf(200);
Integer d = Integer.valueOf(200);
System.out.println(c == d); // false
}
}
Benefits and Limitations
Advantages:
- Reduces memory footprint for high-duplication objects
- Improves performence by minimizing instantiation overhead
Considerations:
- Increases complexity when managing extrinsic state
- Requires careful design to avoid synchronization issues