From harness-claude
Implements GOF Flyweight pattern to share fine-grained objects and reduce memory by separating intrinsic and extrinsic state. Use for large numbers of similar objects like particles, UI elements, or map tiles.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Share fine-grained objects to reduce memory usage by separating intrinsic and extrinsic state.
Implements Flyweight pattern in JavaScript to share intrinsic state across thousands of similar objects, reducing memory usage at scale.
Generates Flyweight pattern for PHP 8.4 to optimize memory usage by sharing intrinsic state across similar objects like icons or glyphs. Includes interface, factory, and unit tests.
Provides PHP 8.3+ implementations, UML guidance, real-world examples, trade-offs, and anti-patterns for 26 Gang of Four design patterns. Activates for applying patterns, refactoring code, selecting patterns, or reviewing usage.
Share bugs, ideas, or general feedback.
Share fine-grained objects to reduce memory usage by separating intrinsic and extrinsic state.
Identify intrinsic vs. extrinsic state first — this is the critical design step:
Particle system example:
// Flyweight — intrinsic state only (shared, immutable)
class ParticleType {
constructor(
public readonly texture: string, // shared texture reference
public readonly color: string, // base color
public readonly shape: 'circle' | 'square'
) {}
// Render uses extrinsic state passed from outside
render(x: number, y: number, opacity: number, scale: number): void {
console.log(`Draw ${this.texture} at (${x},${y}) opacity=${opacity} scale=${scale}`);
}
}
// Flyweight factory — ensures sharing
class ParticleTypeFactory {
private pool = new Map<string, ParticleType>();
get(texture: string, color: string, shape: 'circle' | 'square'): ParticleType {
const key = `${texture}:${color}:${shape}`;
if (!this.pool.has(key)) {
this.pool.set(key, new ParticleType(texture, color, shape));
console.log(`Created new ParticleType for key: ${key}`);
}
return this.pool.get(key)!;
}
poolSize(): number {
return this.pool.size;
}
}
// Context — stores extrinsic state + reference to flyweight
interface ParticleContext {
x: number;
y: number;
opacity: number;
scale: number;
type: ParticleType; // reference, not copy
}
// Client manages contexts, not individual particle objects
class ParticleSystem {
private factory = new ParticleTypeFactory();
private particles: ParticleContext[] = [];
emit(
x: number,
y: number,
texture: string,
color: string,
shape: 'circle' | 'square',
opacity = 1,
scale = 1
): void {
const type = this.factory.get(texture, color, shape); // reuse flyweight
this.particles.push({ x, y, opacity, scale, type });
}
render(): void {
for (const p of this.particles) {
p.type.render(p.x, p.y, p.opacity, p.scale);
}
}
stats(): void {
console.log(`Particles: ${this.particles.length}, Types: ${this.factory.poolSize()}`);
}
}
// 10,000 particles but only 3 ParticleType objects in memory
const system = new ParticleSystem();
for (let i = 0; i < 10_000; i++) {
system.emit(Math.random() * 800, Math.random() * 600, 'spark.png', 'yellow', 'circle');
}
system.stats(); // Particles: 10000, Types: 1
String interning (built-in flyweight in JS):
// JavaScript already interns small strings — the runtime handles this
// For structured data, use a registry:
class TagRegistry {
private tags = new Map<string, Readonly<{ name: string; color: string }>>();
get(name: string, color: string): Readonly<{ name: string; color: string }> {
const key = `${name}:${color}`;
if (!this.tags.has(key)) {
this.tags.set(key, Object.freeze({ name, color }));
}
return this.tags.get(key)!;
}
}
When NOT to use: If you don't have a memory problem, don't introduce this complexity. Measure first. The pattern adds code complexity (factory, split state) that hurts readability without a concrete memory/performance benefit.
Anti-patterns:
Node.js relevance: JavaScript's GC handles many small objects well, but the pattern is still valuable in:
Memory savings calculation:
// Without flyweight: 10,000 particles × 500 bytes (texture data) = ~5MB
// With flyweight: 10,000 contexts × 40 bytes + 1 flyweight × 500 bytes = ~400KB
// Savings: ~12× memory reduction
refactoring.guru/design-patterns/flyweight