CH.07 · STRUCTURAL PATTERNS

Software Design & Architecture · Structural Patterns

Adapter, Composite & Facade

Three patterns, one job in common: reshape how existing classes and objects fit together — without touching what's already there.

Chapter 07 · Lecture 01 Category Structural Design Patterns Previously Creational Patterns Next up Behavioral Design Patterns
00

What Are Structural Patterns?

Structural design patterns deal with how classes and objects are composed to form larger structures — at run time. This chapter covers three of the most popular ones.

🧠 Mnemonic — A.C.F. → "Adapt, Combine, Facilitate" — Adapter adapts a mismatched interface, Composite combines parts into a whole, Facade facilitates (simplifies) access to a complex subsystem.

🔌 Adapter

Makes two incompatible interfaces work together — like a power plug adapter.

🌳 Composite

Lets you treat a single object and a group of objects the same way — a tree of parts and wholes.

🏪 Facade

Wraps a complicated subsystem behind one simple, friendly interface.

01

The Adapter Pattern

Class / Object Structural Pattern

Converts the interface of a class into another interface clients expect — so classes that couldn't otherwise work together, because of incompatible interfaces, now can.

🧠 Mnemonic — think of a travel power plug adapter: your charger (Client) expects one socket shape (Target), the wall (Adaptee) has another — the little plug adapter (Adapter) translates between them without changing either.

❓ Problems the Adapter solves

  • How can a class be reused that doesn't have the interface a client requires?
  • How can classes with incompatible interfaces work together?
  • How can an alternative interface be provided for a class, without changing it?

📐 Structure — Object Adapter vs Class Adapter

Client
Target
+request()
Adapter
+request()
delegates to (Object Adapter)
or inherits (Class Adapter)
Adaptee
+specificRequest()
Aspect Object Adapter Class Adapter
Mechanism Delegates to an Adaptee instance at run-time (composition) Inherits from the Adaptee at compile-time
Requires Just holding a reference to the adaptee object Multiple inheritance — not supported by many languages
Preferred? ✅ Yes — generally preferred Rarely — only where multiple inheritance is available & safe

🐦 Worked Example — Bird → ToyDuck

Setup: a Bird class has fly() and makeSound(). A ToyDuck interface only has squeak(). You're short on real ToyDuck objects and want to use a Bird (Sparrow) in its place. Target = ToyDuck, Adaptee = Bird.

interface ToyDuck { public void squeak(); } // Target
interface Bird { public void fly(); public void makeSound(); } // Adaptee interface

class Sparrow implements Bird {
  public void fly(){ System.out.println("Flying"); }
  public void makeSound(){ System.out.println("Chirp Chirp"); }
}

// The Adapter — implements Target, wraps an Adaptee
class BirdAdapter implements ToyDuck {
  Bird bird; // reference to the object we're adapting
  public BirdAdapter(Bird bird) { this.bird = bird; }
  public void squeak() {
    bird.makeSound(); // translate the call to the adaptee's method
  }
}

// Client
Sparrow sparrow = new Sparrow();
ToyDuck birdAdapter = new BirdAdapter(sparrow); // wrap it
birdAdapter.squeak(); // → "Chirp Chirp" — a bird behaving like a toy duck!
HOW TO USE AN ADAPTER — (1) client calls the adapter using the target interface → (2) adapter translates the request onto the adaptee using the adaptee's interface → (3) client receives the result.

✅ Advantages

Helps achieve reusability & flexibility. Client isn't complicated by a different interface, and can use polymorphism to swap between different adapter implementations.

⚠️ Disadvantages

All requests are forwarded → slight overhead. Sometimes several adaptations are needed in a chain to reach the required type.

02

The Composite Pattern

Object Structural Pattern

Composes objects into tree structures to represent whole-part hierarchies. Lets clients treat individual objects and compositions of objects uniformly.

🧠 Mnemonic — "one leaf, one branch, same rules." Whether you call an operation on a single Leaf or an entire Composite tree, the client code doesn't change.

📐 Structure

Client
<<interface>> Component
+doOperation()
↑ ↑
Leaf
+doOperation()
Composite
+doOperation()
+addComponent()
+removeComponent()
+getChild(i)
holds 0..* Components ♦

Both Leaf (a single object) and Composite (a collection of Components) implement the same Component interface — that's the whole trick.

🗂️ Real-life example — File System

A file is a primitive (Leaf) — it holds no other objects. A folder is a Composite — it can contain files and other folders. Opening either uses the same open() operation.

🎓 Real-life example — University Program

A single course ("Math 101") is a Leaf. A program ("CS degree") is a Composite of many courses. Checking details works the same way for both.

☕ Java — Component / Leaf / Composite

public interface Component {
  public void sayHello();
  public void sayGoodbye();
}

public class Leaf implements Component {
  String name;
  public Leaf(String name){ this.name = name; }
  public void sayHello(){ System.out.println(name + " leaf says hello"); }
  public void sayGoodbye(){ System.out.println(name + " leaf says goodbye"); }
}

public class Composite implements Component {
  List<Component> components = new ArrayList<>();
  public void add(Component c){ components.add(c); }
  public void sayHello(){ for(Component c : components) c.sayHello(); }
  public void sayGoodbye(){ for(Component c : components) c.sayGoodbye(); }
}

// Client
Composite composite1 = new Composite();
composite1.add(new Leaf("Bob"));
composite1.add(new Leaf("Fred"));
composite1.sayHello(); // → "Bob leaf says hello" then "Fred leaf says hello"
// composites can even nest inside other composites!

🪜 Steps to design it

🧠 P.C.C.L.C. → Plan the tree → Component → Composite → Leaf → Client.
  1. Plan the tree-like structure needed
  2. Design the Component base (shared, overridable methods)
  3. Design Composite — overrides shared methods + add/remove children + internal storage
  4. Design Leaf classes — override the Component methods
  5. Design the Client that uses both uniformly

✅ Benefits

  • Supports both primitive and composite objects in one structure
  • Minimizes client complexity — same call works on both
  • Easy to add new component objects to the application
03

The Facade Pattern

Object Structural Pattern

Provides a unified, simplified interface to a set of interfaces in a subsystem — a higher-level interface that makes the whole subsystem easier to use.

🧠 Mnemonic — think of a shop keeper: you (the client) just ask for "an iPhone," you don't deal with the manufacturer's internal parts logic — the shop keeper (Facade) handles that complexity for you.

📐 Structure

Client
Facade
+operation()
ClassA
+op1() +op2()
ClassB
+op3() +op4()

The client never touches ClassA / ClassB directly — only the Facade.

📱 Worked Example — MobileShop

Setup: a MobileShop interface is implemented by Iphone, Samsung, Blackberry. Instead of the client juggling all three directly, a ShopKeeper Facade wraps them.

public interface MobileShop { void modelNo(); void price(); }

public class Iphone implements MobileShop { /* Iphone 6, Rs 65000 */ }
public class Samsung implements MobileShop { /* Galaxy Tab 3, Rs 45000 */ }
public class Blackberry implements MobileShop { /* Z10, Rs 55000 */ }

// The Facade
public class ShopKeeper {
  private MobileShop iphone, samsung, blackberry;
  public ShopKeeper(){
    iphone = new Iphone(); samsung = new Samsung(); blackberry = new Blackberry();
  }
  public void iphoneSale(){ iphone.modelNo(); iphone.price(); }
  public void samsungSale(){ samsung.modelNo(); samsung.price(); }
  public void blackberrySale(){ blackberry.modelNo(); blackberry.price(); }
}

// Client — never touches Iphone/Samsung/Blackberry directly
ShopKeeper sk = new ShopKeeper();
sk.iphoneSale(); // → "Iphone 6" · "Rs 65000.00"

🪜 Steps to design it

🧠 I.L.D.I.A. → Identify components → List operations → Design Facade class → Implement it → Allow client access.
  1. Identify all components in the subsystem operation
  2. List operations required to execute it
  3. Design a Facade class with an interface method
  4. Implement it by calling the listed subsystem operations
  5. Let clients access the subsystem only through the Facade

✅ Benefits

🧠 S.S.W. → Shields clients, Stable interface, Weak coupling.
  • Shields clients from complex subsystem internals
  • Provides a stable interface — internal changes don't break clients
  • Promotes weak coupling — clients depend on one interface, not many
04

All Three, Side by Side

A quick way to tell them apart on an exam: ask "what is this pattern actually solving?"

Pattern Solves Shape Cue phrase
Adapter Two incompatible interfaces need to work together Client → Adapter → Adaptee "convert this interface into that one"
Composite Need to treat single objects & groups of objects the same way Tree: Component ← Leaf / Composite "whole-part hierarchy, uniform treatment"
Facade A subsystem is too complex for clients to use directly Client → Facade → {ClassA, ClassB, …} "one simple interface for a messy subsystem"
05

Quick-Fire Flashcards

Tap a card to flip it.

06

Practice Questions

Written from this chapter's content — self-check practice, not an official past paper.

07

One-Screen Recap