← Back to PatternPip

DECORATOR / PRACTICE

One line of text.
Layers of possibility.

You met Decorator through notification senders. Now compose optional extras around a text preview.

YOUR BRIEF

Add extras without teaching the client about each one.

A preview starts with hello. Some callers want a “Note: ” label, some want uppercase, and some want both. Keep the client calling render() while setup chooses the wrappers and their order.

Uppercase outside the label produces NOTE: HELLO. Put the label outside instead and it produces Note: HELLO. Test both, then add a border as another wrapper.

The working starting point

function showPreview(view: TextView): string {
  return view.render();
}
const preview = showPreview(new PlainText("hello"));

PlainText owns the original string. Each decorator holds a TextView and adds behavior to its returned string. This is object composition, not @decorator syntax.

01 / ASSEMBLE

Give each extra its own wrapper.

Both wrappers use your selected structure. LabelText adds “Note: ”; UppercaseText uppercases the returned text.

Your assembled code

TypeScript preview. Highlighting follows the selected execution.

Shared component interface

interface TextView { render(): string }

Concrete component · original text

class PlainText implements TextView {
  constructor(private text: string) {}
  render(): string { return this.text; }
}

LabelText

// Choose all three pieces to assemble this wrapper.

UppercaseText

// Choose all three pieces to assemble this wrapper.

Client · unaware of the chosen extras

function showPreview(view: TextView): string { return view.render(); }

Setup · choose the wrapper order

// Complete a compatible assembly before passing it to the client.

02 / RUN & OBSERVE

Same wrappers. Different order.

LabelText(PlainText) should add Note: to hello.

Expected preview: Note: hello

Calls go down ↓ · Results come back up ↑

Client · showPreviewKnows only TextView.render()No result yet
LabelTextAdds Note: to the inner resultNo result yet
PlainTextThe supplied object · original text: helloNo result yet

Choose your pieces, then follow one call through the composed objects.

Output and delegation feedback will appear here.

  • ○ Add a label — run to verify
  • ○ Uppercase outside the label — run to verify
  • ○ Label outside uppercase — run to verify

Each test creates a fresh local chain. Every wrapper must call its supplied inner object once in this exercise. The trace records actual calls and return values; matching text alone does not prove correct delegation.

03 / TRANSFER THE IDEA

One more extra: a border.

Add BorderText outside the uppercase-and-label chain. It should turn NOTE: HELLO into [NOTE: HELLO]. Which edits are needed?

First pass the label case and both wrapper-order cases with the same assembly.

Select all required edits

Compare with a complete solution

No timer and no attempt limit. Try another assembly, use a hint, or reveal the answer when it helps.