WalzoneInterview Prep
📞 Interviewing soon? Practice with a realistic AI mock phone interview — it calls you, then scores you. First 15 min FREE →

Design Patterns · Guru · question 97 of 100

Explain how the Bridge pattern can be used to address challenges related to multiple dimensions of variability and extensibility in complex system architectures.?

📕 Buy this interview preparation book: 100 Design Patterns questions & answers — PDF + EPUB for $5

The Bridge design pattern is a structural pattern that decouples an abstraction from its implementation so that both can vary independently. In other words, it separates an abstract class from its implementation, allowing for changes to be made to each independently without affecting the other. This makes it useful in addressing challenges related to multiple dimensions of variability and extensibility in complex system architectures.

A complex system architecture often involves multiple dimensions of variability, such as different platforms, operating systems, databases or protocols, leading to a large number of classes and interfaces. Additionally, as the system evolves or new requirements arise, it may have to be extended in multiple directions, requiring potentially large-scale changes to the codebase. In such cases, it is important to have a design that can separate these concerns and allow for flexibility and extensibility.

The Bridge pattern consists of two parts: an abstraction and an implementation, which are connected by a bridge. The abstraction defines the interface that the client interacts with, while the implementation defines the actual implementation of that interface. The bridge connects the two by allowing different implementations to be used with the same abstraction.

Let’s consider an example. Suppose we have a drawing application that can draw different shapes on different platforms (such as a desktop application, a web application or a mobile application). We can start by defining an abstract Shape class and its implementation classes, each of which is tied to a particular platform. However, this creates a tight coupling between the abstraction and its implementation, making it difficult to add new shapes or platforms without changing the existing code.

By introducing a bridge, we can decouple the Shape abstraction from its implementations. We can define a separate interface for each platform, such as DesktopShape, WebShape and MobileShape, and a separate implementation class for each shape, such as Circle, Square, and Triangle. The Shape abstraction would then reference the platform-specific interface, and the implementation classes would implement this interface. This allows us to add new shapes or platforms without changing the existing code, as long as we provide a new implementation class that adheres to the platform-specific interface.

Here is an example implementation of the Bridge pattern in Java:

// Abstraction
public abstract class Shape {
    protected ShapeImpl shapeImpl;
    
    public Shape(ShapeImpl shapeImpl) {
        this.shapeImpl = shapeImpl;
    }
    
    public abstract void draw();
}

// Implementor
public interface ShapeImpl {
    public void drawCircle();
    public void drawSquare();
    public void drawTriangle();
}

// Concrete Implementors
public class DesktopShapeImpl implements ShapeImpl {
    @Override
    public void drawCircle() {
        // draw circle on desktop
    }
    
    @Override
    public void drawSquare() {
        // draw square on desktop
    }
    
    @Override
    public void drawTriangle() {
        // draw triangle on desktop
    }
}

public class WebShapeImpl implements ShapeImpl {
    @Override
    public void drawCircle() {
        // draw circle on web
    }
    
    @Override
    public void drawSquare() {
        // draw square on web
    }
    
    @Override
    public void drawTriangle() {
        // draw triangle on web
    }
}

// Refined Abstractions
public class Circle extends Shape {
    public Circle(ShapeImpl shapeImpl) {
        super(shapeImpl);
    }
    
    public void draw() {
        shapeImpl.drawCircle();
    }
}

public class Square extends Shape {
    public Square(ShapeImpl shapeImpl) {
        super(shapeImpl);
    }
    
    public void draw() {
        shapeImpl.drawSquare();
    }
}

public class Triangle extends Shape {
    public Triangle(ShapeImpl shapeImpl) {
        super(shapeImpl);
    }
    
    public void draw() {
        shapeImpl.drawTriangle();
    }
}

// Client
public class Client {
    public static void main(String[] args) {
        Shape desktopCircle = new Circle(new DesktopShapeImpl());
        desktopCircle.draw(); // draws circle on desktop
        
        Shape webSquare = new Square(new WebShapeImpl());
        webSquare.draw(); // draws square on web
    }
}

In this example, the Shape abstraction defines the draw() method, which is implemented by the Circle, Square and Triangle classes. The ShapeImpl interface defines the methods for drawing each shape on a specific platform, which are implemented by the DesktopShapeImpl and WebShapeImpl classes. The bridge between the abstraction and implementation is established by passing an implementation object to the Shape constructor.

By using the Bridge pattern, we have decoupled the abstraction from its implementation, allowing us to add new shapes or platforms by creating new implementation classes that adhere to the platform-specific interface, without changing the existing code. This makes it easier to manage multiple dimensions of variability and extensibility in complex system architectures.

Reading is step one. Saying it out loud is the interview. Our AI interviewer calls your phone and runs a realistic Design Patterns interview — then scores it.
📞 Practice Design Patterns — free 15 min
📕 Buy this interview preparation book: 100 Design Patterns questions & answers — PDF + EPUB for $5

All 100 Design Patterns questions · All topics