ProgramGuru

Bridge Pattern

Bridge: start from the problem

See the responsibilities

Alert behaviourRoutine or urgent formatting
Delivery contractsend(message)
Channel implementationEmail or SMS
RecipientReceives the formatted alert
Alert behaviour: Routine or urgent formatting → Delivery contract: send(message) → Channel implementation: Email or SMS → Recipient: Receives the formatted alert

A notification service supports routine and urgent alerts, and can deliver each through email or SMS. Creating a separate class for every alert-and-channel pair grows the combinations and repeats delivery details.

This is a structural pattern lesson. Follow the responsibilities, inspect the small JavaScript example and compare the design choices. The example is local teaching code; its boundary is explained before you apply the idea to a real service.

What you’ll learn

  • Explain the problem Bridge addresses and the roles involved.
  • Follow the example and distinguish this pattern from nearby alternatives.
  • Choose when the benefit justifies the extra responsibilities and testing.

How the responsibilities work

Bridge separates the high-level behaviour from the implementation it uses. The high-level object holds an implementation through a contract and delegates work to it. The two dimensions can then gain variants independently.

Here Alert and UrgentAlert express message behaviour. EmailDelivery and SmsDelivery express delivery. UrgentAlert can use either implementation without becoming an UrgentEmailAlert and an UrgentSmsAlert hierarchy.

Follow a small example

Read the JavaScript from top to bottom and compare the expected output. The values are chosen to make this pattern’s responsibility visible. This example runs in one local execution context; it does not create remote services, durable storage or production access controls.

JavaScript · local teaching example

class Alert {
  constructor(delivery) { this.delivery = delivery; }
  notify(text) { return this.delivery.send(text); }
}
class UrgentAlert extends Alert {
  notify(text) { return super.notify('URGENT: ' + text); }
}
const email = {send: text => 'Email → ' + text};
const sms = {send: text => 'SMS → ' + text};
console.log(new UrgentAlert(email).notify('Disk full'));
console.log(new UrgentAlert(sms).notify('Disk full'));

Expected output

Email → URGENT: Disk full
SMS → URGENT: Disk full

Combine an alert with a delivery channel

One bridge, four combinations

Alert behaviourRoutine or urgent formatting
Delivery implementationEmail or SMS

Routine + Email

Email → Disk full

Routine + SMS

SMS → Disk full

Urgent + Email

Email → URGENT: Disk full

Urgent + SMS

SMS → URGENT: Disk full

Your composed result

Email → Disk full

This local composition does not send email or SMS. New channels must satisfy the delivery contract used by alert behaviours.

The behaviour formats the message; the channel handles delivery. All combinations below use the fixed message “Disk full”.

Choose routine or urgent behaviour, then email or SMS delivery. The matrix keeps all four supported combinations visible. The local result applies the same composition as the example; it does not send a real message.

Add a new channel by implementing send. Add an alert behaviour by delegating through that contract. Test both dimensions and their supported combinations.

Choose a design and inspect the consequence

Compare the design choices

A push-delivery channel is added.
An audit alert gains different formatting.

Compare the visible consequences. With JavaScript enabled, choose an option in each scenario to assemble your decision record.

This is an exploratory design exercise. It does not run infrastructure, measure capacity or replace the lesson’s quiz.

Use the consequences to explain your decision, including the simpler alternative.

Apply the pattern to two situations. Select one option in each situation to build a decision record. Every option and its consequence stays visible, and you can change your choices.

When it helps—and what it costs

Use it when two real variation dimensions need independent extension, such as report formats and delivery channels. Keep the implementation contract narrow enough to support the high-level behaviours.

A bridge adds a delegation boundary and configuration responsibility. If there is only one stable dimension, direct composition or a Strategy can be clearer. Independent extension still requires compatible semantics and tests for supported combinations.

Distinguish the neighbouring patterns

Adapter wraps an already mismatched interface. Strategy commonly swaps an algorithm within a behaviour. Bridge explicitly separates two independently extensible dimensions. The system/code distinction explains why this object structure does not by itself distribute the service.

Follow Adapter for an existing interface mismatch, Strategy for an interchangeable algorithm, compatible implementation families to compare the specific responsibility before combining patterns.

For further reading, use the Bridge reference supplied for this course. Compare it with this original example and the guarantee required by your application.

Check your pattern reasoning

Which two dimensions vary in the alert example?
Choose one answer. You can try again.

Answer and explanation

Alert behaviour and delivery implementation.

They are composed through a delivery contract.

Check your pattern reasoning

What growth does Bridge help avoid?
Choose one answer. You can try again.

Answer and explanation

A separate concrete class for every combination of the two dimensions.

Variants compose rather than requiring a full cross-product hierarchy.

Compare the pattern boundaries

You already have an incompatible vendor interface and need to present your existing application contract. Which pattern most directly describes that mismatch?
Choose one answer. You can try again.

Answer and explanation

Adapter.

Adapter reconciles an existing interface; Bridge separates independently evolving dimensions.

Name the responsibility before choosing the pattern

For Bridge, describe the problem, the participating roles and the observable contract. Use the example as a starting point and test the boundaries identified in the trade-offs. A pattern name alone does not establish correctness or performance.

Return to the design-pattern guide to compare families, or apply the idea alongside compatible implementation families.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: Composite Pattern →