Bridge pattern implementation separates the Abstraction and implementation. That way we can switch the implementation at runtime and use the implementation flexibly.
This article is about Bridge pattern implementation in TypeScript. Check the implementation details and examples.
Implementation
Following these steps to implement Bridge pattern in TypeScript-
- Create an interface for the for first set of classes.
- Create classes and implement the first inerface.
- Create another interface for second set of classes.
- Create second set of classes and implement the second interface.
- In the class implementations of second set of classes, keep a reference of type first interface. In the method implementations use methods from the first set of classes.
Here is the code for implementing the modules and plugin usage-
// Bridge pattern in TS
// Plugin interface
interface PluginI {
pluginOperation1(): void;
}
// First plugin
class Plugin1 implements PluginI {
pluginOperation1(): void {
console.log("Plugin 1: operation 1");
}
}
// Second plugin
class Plugin2 implements PluginI {
pluginOperation1(): void {
console.log("Plugin 2: operation 1");
}
}
// Module interface
abstract class ModuleI {
protected plugin: PluginI;
constructor(plugin: PluginI) {
this.plugin = plugin;
}
abstract moduleOperation1(): void;
}
// First module
class Module1 extends ModuleI {
moduleOperation1(): void {
console.log("Module 1: operation 1")
this.plugin.pluginOperation1()
}
}
// Second module
class Module2 extends ModuleI {
moduleOperation1(): void {
console.log("Module 2: operation 1")
this.plugin.pluginOperation1()
}
}
// Demo
const module1 = new Module1(new Plugin2());
module1.moduleOperation1();
Output of the above code will be as below.
Module 1: operation 1
Plugin 2: operation 1
Examples
Here are a few examples of Bridge pattern implementation in TypeScript.
Example #1: UI Elements
Color Interface
- Create file “color.ts”.
- Create interface “Color”.
- Declare method – “setColor”.
// color.ts
interface Color {
setColor(): void;
}
export default Color;
Red [Color Schema]
- Create file “red.ts”.
- Create class “Red”.
- Implement interface “Color” for the “Red” class- define “setColor” method for the class.
// red.ts
import Color from "./color";
class Red implements Color {
public setColor(): void {
console.log("Setting proper color for Red color schema");
}
}
export default Red;
Green [Color Schema]
- Create file “green.ts”.
- Create class “Green”.
- Implement “Color” interface for “Green” class.
// green.ts
import Color from "./color";
class Green implements Color {
public setColor(): void {
console.log("Setting proper color for Green color schema");
}
}
export default Green;
Blue [Color Schema]
- Create file “blue.ts”.
- Create class “Blue”.
- Implement “setColor” method for “Blue” as part of “Color” interface implementation.
// blue.ts
import Color from "./color";
class Blue implements Color {
public setColor(): void {
console.log("Setting proper color for Blue color schema");
}
}
export default Blue;
UI Element Interface
- Create file “ui-element.ts”.
- Create abstract class “UIElement”.
- Define a class property “color” of type “Color”.
- In the constructor accept param and set that to the “color” property”.
- Declare an abstract method “printElement”.
// ui-element.ts
import Color from "./color";
abstract class UIElement {
protected color: Color;
constructor(color: Color) {
this.color = color;
}
abstract printElement(): void;
}
export default UIElement;
Button [UI Element]
- Create file “button.ts”.
- Create class “Button”.
- Extend “UIElement” for the “Button” class.
- In the constructor accept color and call the parent construct.
- Define “printElemement” method. In the method call “setColor” of “color” when required, and perform other relevant operations.
// button.ts
import Color from "./color";
import UIElement from "./ui-element";
class Button extends UIElement {
constructor(color: Color) {
super(color);
}
public printElement(): void {
this.color.setColor();
console.log("Printing Button");
}
}
export default Button;
Input [UI Element]
- Create file “input.ts”.
- Create class “Input”.
- Extend “UIElement” for the “Input” class.
- In the constructor accept color and call the parent construct.
- Define “printElemement” method.
// input.ts
import Color from "./color";
import UIElement from "./ui-element";
class Input extends UIElement {
constructor(color: Color) {
super(color);
}
public printElement(): void {
this.color.setColor();
console.log("Printing Input");
}
}
export default Input;
Table [UI Element]
- Create file “table.ts”.
- Create class “Table”.
- Extend “UIElement” for the “Table”.
- In the constructor accept color and call the parent construct.
- Define “printElemement” method as part of the abstract class.
// table.ts
import Color from "./color";
import UIElement from "./ui-element";
class Table extends UIElement {
constructor(color: Color) {
super(color);
}
public printElement(): void {
this.color.setColor();
console.log("Printing Table");
}
}
export default Table;
Demo
For checking the implementation we can pass a color object (Red/Green/Blue) to the UI Element while using it.
// demo.ts
import Blue from "./blue";
import Button from "./button";
import Green from "./green";
import Input from "./input";
import Red from "./red";
import Table from "./table";
var table = new Table(new Red());
table.printElement();
var input = new Input(new Green());
input.printElement();
var button = new Button(new Blue());
button.printElement();
var button2 = new Button(new Red());
button2.printElement();
Output
The output of the demo above will be like below.
Setting proper color for Red color schema
Printing Table
Setting proper color for Green color schema
Printing Input
Setting proper color for Blue color schema
Printing Button
Setting proper color for Red color schema
Printing Button
Example #2: Transport Seat
Here we have 2 modes of transport- Train and Plane. And there are 2 types of seats available for transport – Economy and Business class. Users can select any type of seat for any type of transport.
Seat Interface
- Create file “seat.ts”.
- Create interface “Seat”. This interface will be used by all classes of seats.
- Declare class “selectSeat” for the interface.
// seat.ts
interface Seat {
selectSeat(): void;
}
export default Seat;
Business Class Seat [Seat Type]
- Create file “business-class-seat.ts”.
- Define class “BusinessClassSeat”.
- Implement “Seat” interface for the class.
- Define method “selectSeat” as part of the interface implementation.
// business-class-seat.ts
import Seat from "./seat";
class BusinessClassSeat implements Seat {
public selectSeat(): void {
console.log("Select an Business class seat");
}
}
export default BusinessClassSeat;
Economy Class Seat [Seat Type]
- Create file “economy-class-seat.ts”.
- Create class “EconomyClassSeat”.
- Implement interface “Seat” for “EconomyClassSeat”.
// economy-class-seat.ts
import Seat from "./seat";
class EconomyClassSeat implements Seat {
public selectSeat(): void {
console.log("Select an Economy class seat");
}
}
export default EconomyClassSeat;
Transport Interface
- Create file “transport.ts”.
- Define abstract class “Transport”.
- Create a class property “seat” of type “Seat”.
- Accept “seat” in the constructor and set the property value.
- Declare an abstract method “selectTransport”.
// transport.ts
import Seat from "./seat";
abstract class Transport {
protected seat: Seat;
constructor(seat: Seat) {
this.seat = seat;
}
public abstract selectTransport(): void;
}
export default Transport;
Plane [Transport]
- Create file “plane.ts”.
- Create “Plane” class.
- Extend abstract class “Transport” for “Plane” class.
- Define “selectTransport” method. Use the “selectSeat” from “Seat” when required.
// plane.ts
import Seat from "./seat";
import Transport from "./transport";
class Plane extends Transport {
constructor(seat: Seat) {
super(seat);
}
selectTransport(): void {
console.log("Plane selected for transport");
this.seat.selectSeat();
}
}
export default Plane;
Train [Transport]
- Create file “train.ts”.
- Create “Train” class.
- Extend abstract class “Transport” for “Train” class.
- Define method “selectTransport”.
// train.ts
import Seat from "./seat";
import Transport from "./transport";
class Train extends Transport {
constructor(seat: Seat) {
super(seat);
}
selectTransport(): void {
console.log("Train selected for transport");
this.seat.selectSeat();
}
}
export default Train;
Demo
Now we can pass any set object (BusinessClassSeat/EconomyClassSeat) to any transport object (Plane/Train) while creating new object.
// demo.ts
import BusinessClassSeat from "./business-class-seat";
import EconomyClassSeat from "./economy-class-seat";
import Plane from "./plane";
import Train from "./train";
var plane = new Plane(new BusinessClassSeat());
plane.selectTransport();
var plane2 = new Plane(new EconomyClassSeat());
plane2.selectTransport();
var train = new Train(new EconomyClassSeat());
train.selectTransport();
Output
We will get the following output.
Plane selected for transport
Select an Business class seat
Plane selected for transport
Select an Economy class seat
Train selected for transport
Select an Economy class seat
Source Code
Use the following link to get the source code:
Other Code Implementations
Use the following links to check Bridge pattern implementation in other programming languages.