Table of content

Bridge Design Pattern

The bridge pattern allows the Abstraction and the Implementation to be developed independently and the client code can access only the Abstraction part without being concerned about the Implementation part.

Decouple an abstraction from its implementation so that the two can vary independently

Need for Bridge Design Pattern

When there are inheritance hierarchies creating a concrete implementation, you lose flexibility because of interdependence.

Decouple implementation from the interface and hiding implementation details from the client is the essence of the bridge design pattern.

When to use the Bridge Pattern

  • When there is a need to void the permanent binding or tight coupling between abstraction and implementation. In this case, an implementation may select or switch at run-time
  • When there is a need for extending the abstraction and the composite implementation separately by subclasses.
  • When the change in extended implementations should not impact the client
  • When there is a hierarchical propagation of several categories of classes in the system

Advantageous of Bridge Design Pattern

  • Bridge patterns allow independent variation between two abstract and implementor systems
  • It avoids the client code binding to a certain implementation
  • Abstraction and implementation can be clearly separated allowing easy future extension
  • Provides a good solution for cross-platform development
  • Well suited for testing with stubs in the initial development cycle
struct Display {
	imple : Box<DisplayImpl>,
}

impl Display { fn new(imple: Box<DisplayImpl>) -> Display { Display { imple: imple, } }

fn open(&self) { self.imple.raw_open(); }

fn print(&self) { self.imple.raw_print(); }

fn close(&self) { self.imple.raw_close(); }

fn display(&self) { self.open(); self.print(); self.close(); } }

struct CountDisplay { display: Box<DisplayImpl>, }

impl CountDisplay { fn new(display: Box<DisplayImpl>) -> CountDisplay { CountDisplay { display: display, } }

fn multi_display(&self, times: u32) { self.display.raw_open(); for _ in 0..times { self.display.raw_print(); } self.display.raw_close(); }

fn display(&self) { self.display.raw_open(); self.display.raw_print(); self.display.raw_close(); } }

trait DisplayImpl { fn raw_open(&self); fn raw_print(&self); fn raw_close(&self); }

struct StringDisplayImpl { string: String, width: usize, }

impl StringDisplayImpl { fn new(string: String) -> StringDisplayImpl { StringDisplayImpl { string: string.clone(), width: string.chars().count(), } }

fn print_line(&self) { print!("+"); for _ in 0..self.width { print!("-"); } println!("+"); } }

impl DisplayImpl for StringDisplayImpl { fn raw_open(&self) { self.print_line(); }

fn raw_print(&self) { println!("|{}|", self.string); }

fn raw_close(&self) { self.print_line(); } }

fn main() { let d1 = Display::new(Box::new(StringDisplayImpl::new("Hello, Japan".to_string()))); let d2 = CountDisplay::new(Box::new(StringDisplayImpl::new("Hello, World.".to_string()))); let d3 = CountDisplay::new(Box::new(StringDisplayImpl::new("Hello, Universe.".to_string()))); d1.display(); d2.display(); d3.display(); d3.multi_display(5); }