Chaturmind
LearnDSASystem DesignBlogPremium
Sign inGet started
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML

Company

  • Blog
  • Premium
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Low-Level Design & Design Patterns

OOP Fundamentals & SOLID Principles

  • Object-Oriented Design Refresher
  • Single Responsibility & Open/Closed
  • Liskov Substitution & Interface Segregation
  • Dependency Inversion

Creational Design Patterns

  • Singleton Pattern
  • Factory & Abstract Factory
  • Builder Pattern
  • Prototype Pattern

Structural Design Patterns

  • Adapter & Facade
  • Decorator Pattern
  • Composite & Proxy
  • Bridge & Flyweight
Chaturmind
← Low-Level Design & Design Patterns

OOP Fundamentals & SOLID Principles

  • Object-Oriented Design Refresher
  • Single Responsibility & Open/Closed
  • Liskov Substitution & Interface Segregation
  • Dependency Inversion

Creational Design Patterns

  • Singleton Pattern
  • Factory & Abstract Factory
  • Builder Pattern
  • Prototype Pattern

Structural Design Patterns

  • Adapter & Facade
  • Decorator Pattern
  • Composite & Proxy
  • Bridge & Flyweight
HomeLearnSystem DesignLow-Level Design & Design PatternsStructural Design Patterns
✓ FreeAdvanced· 7 min read

Bridge & Flyweight

Bridge decouples an abstraction from its implementation so both can evolve independently; Flyweight shares common state across many objects to cut memory footprint — via a text-editor glyph example.

Published September 22, 2026


Bridge & Flyweight

Bridge: decoupling abstraction from implementation

The problem Bridge solves: an abstraction (say, Shape) and its implementation (say, RenderingEngine) both need to vary independently — new shapes get added, and new rendering backends get added, and neither should force changes in the other.

Without Bridge — the combinatorial trap

If Shape subclasses each hard-code their rendering approach (VectorCircle, RasterCircle, VectorSquare, RasterSquare...), every new shape times every new rendering backend multiplies the class count — the same explosion problem Decorator solves for behavior, but here it's for two independently-varying dimensions.

The Bridge fix

interface RenderingEngine { // the "implementation" side
    void renderCircle(double x, double y, double radius);
}

class VectorRenderer implements RenderingEngine {
    public void renderCircle(double x, double y, double radius) { /* draw as vector paths */ }
}
class RasterRenderer implements RenderingEngine {
    public void renderCircle(double x, double y, double radius) { /* draw as pixels */ }
}

abstract class Shape { // the "abstraction" side
    protected final RenderingEngine renderer; // the bridge — composed, not inherited
    Shape(RenderingEngine renderer) { this.renderer = renderer; }
    abstract void draw();
}

class Circle extends Shape {
    private double x, y, radius;
    Circle(RenderingEngine renderer, double x, double y, double radius) {
        super(renderer);
        this.x = x; this.y = y; this.radius = radius;
    }
    void draw() { renderer.renderCircle(x, y, radius); } // delegates across the bridge
}
Shape vectorCircle = new Circle(new VectorRenderer(), 0, 0, 5);
Shape rasterCircle = new Circle(new RasterRenderer(), 0, 0, 5);

Adding a new shape (Square) means one new Shape subclass, reusable with any existing RenderingEngine. Adding a new backend (GpuRenderer) means one new RenderingEngine implementation, usable by any existing shape. The two hierarchies vary completely independently — this is the same "hold a reference instead of extending" idea as Dependency Inversion and Strategy, applied specifically to keep two dimensions of variation from multiplying against each other.

Flyweight: sharing state to cut memory footprint

Flyweight's premise: when you need many objects that share most of their state, factor the shared part out into one reused object, and keep only the truly per-instance state separate.

Text editor glyph example

A document with 100,000 characters, each naively represented as its own object holding a font, size, color, and the character itself, wastes enormous memory — most of that font/size/color state is identical across thousands of characters.

// Intrinsic state (shared, immutable) — the Flyweight
class GlyphStyle {
    private final String font;
    private final int size;
    private final String color;
    GlyphStyle(String font, int size, String color) { this.font = font; this.size = size; this.color = color; }
    void render(char c, int x, int y) { /* draw c at (x,y) using font/size/color */ }
}

// Flyweight factory — ensures identical styles are actually shared, not duplicated
class GlyphStyleFactory {
    private final Map<String, GlyphStyle> cache = new HashMap<>();

    GlyphStyle get(String font, int size, String color) {
        String key = font + size + color;
        return cache.computeIfAbsent(key, k -> new GlyphStyle(font, size, color));
    }
}

// Extrinsic state (per-character, NOT shared) stays outside the flyweight
class Character {
    char c;
    int x, y;
    GlyphStyle style; // shared reference, not a copy
}

If a document has 100,000 characters but only 5 distinct (font, size, color) combinations in use, only 5 GlyphStyle objects ever exist — every Character holds a reference to one of those 5 shared instances, rather than duplicating the style data 100,000 times. The position (x, y) and the actual character can't be shared (they're genuinely unique per character) — that's the extrinsic state, kept outside the flyweight and passed in or stored separately.

Follow-up questions this topic invites — and their answers

Q: How is Bridge different from Strategy, since both hold a composed reference instead of inheriting? A: They're structurally similar but differ in intent and timing: Strategy typically swaps one algorithm/behavior at a single point, often chosen per call or per short-lived object; Bridge is about permanently decoupling two entire class hierarchies so each can grow independently over the object's lifetime. In practice the line blurs, and some texts treat Bridge as "Strategy applied at the architectural level."

Q: What's the risk if intrinsic and extrinsic state get mixed up in a Flyweight? A: If something that should be extrinsic (per-instance, like position) accidentally gets stored inside the shared flyweight object, every "instance" sharing that flyweight would incorrectly share that state too — e.g. all characters using the same GlyphStyle would appear at the same position. Flyweight only works correctly when intrinsic/extrinsic separation is exact.

Q: Doesn't the GlyphStyleFactory's cache risk becoming a memory leak itself? A: Only if styles are added without bound and never removed — for a fixed, small set of styles (fonts/sizes/colors actually used in a document) this isn't a concern, but a system generating unbounded distinct style combinations would need an eviction policy on the cache, same as any other unbounded cache.

Q: Is Flyweight still relevant given how cheap memory is today? A: Less critical for typical business applications, but still very relevant at genuine scale — game engines rendering hundreds of thousands of similar entities, or systems caching large numbers of near-identical configuration objects, still see real, measurable benefit from it.

Previous

Composite & Proxy

AI Tutor

Lesson: Bridge & Flyweight

Quick actions

AI responses can be inaccurate. Verify critical information.