Transcript bridge
Leftover Patterns
Bridge
0
Synopsis
Bridge pattern
The Bridge pattern is useful when there is a hierarchy
of abstractions and a corresponding hierarchy of
implementations
The Bridge pattern implements the abstractions and
implementations as independent classes that can be
combined dynamically.
1
Context(1/5)
Suppose you need to provide Java classes that
access physical sensors for control applications
Scale
produces a single number based on a measurement at a
single point in time.
Speed-measuring device
produces a single measurement that is an average over a
period of time.
Location-sensing device
produces a stream of measurements.
2
Context(2/5)
these devices can be supported by three classes
support these different measurement techniques.
Sensor Classes
3
Context(3/5)
Suppose the software that you are writing will need to
work with sensors from multiple manufacturers called
Eagle and Hawk.
It doesn’t reuse classes for simple, averaging, and streaming sensor
it exposes the differences between manufacturers to other class
Manufacturer-specific sensor classes
4
Context(4/5)
A way to accomplish that is to add some indirection that
shields a hierarchy of classes that support abstractions
from classes that implement those abstractions
5
Context(5/5)
Dividing the problem into three hierarchies
There is a hierarchy for the manufacturer-independent
sensor classes
SimpleSensor, AveragingSensor, StreamingSensor
There is a parallel hierarchy for the manufacturerspecific classes
SimpleSensorImpl, AveragingSensorImple,
StreamingSensorImpl that have names beginning with Eagle
and Hawk
There is a parallel hierarchy of interfaces that allow the
manufacturer-independent classes to remain
independent of any manufacturer-specific classes
SimpleSensorImpl,
AveragingSensorImpl, ,StreamingSensorImpl
6
Force(1/2)
Combining hierarchies of abstractions and
hierarchies of their implementations into a single
class hierarchy
Changing the implementation used for an
abstraction should not require changes to the
classes that use the abstraction.
Reusing logic common to different
implementations of an abstraction.
The usual way to make logic reusable is to encapsulate
it in a separate class.
7
Force(2/2)
Creating a new implementation of an abstraction
without having to re-implement the common
logic of the abstraction.
Extending the common logic of an abstraction by
writing one new class rather than writing a new
class for each combination of the base
abstraction and its implementation
multiple abstractions should be able to share the
same implementation.
8
Solution(1/7)
The Bridge pattern allows classes corresponding to
abstractions to be separate from classes that implement
those abstractions.
9
Solution(2/7)
Abstraction
This class represents the top-level abstraction
It is responsible for maintaining a reference to an
object that implements the AbstractionImpl interface
SpecializedAbstraction
This role corresponds to any subclass of the
Abstraction class
For each such subclass of the Abstraction class there
is a corresponding sub-interface of the
AbstractionImpl interface
Each SpecializedAbstraction class delegates its
operations to an implementation object
10
Solution(3/7)
AbstractionImpl
This interface declares methods for all of the low-level
operations that an implementation for the Abstraction
class must provide.
SpecializedAbstractionImpl
This corresponds to a sub-interface of AbstractionImpl
Each SpecializedAbstractionImpl interface corresponds
to a SpecializedAbstraction class
Each SpecializedAbstractionImpl interface declares
methods for the low-level operations needed for an
implementation of that class.
11
Solution(4/7)
SpecializedAbstractionImpl
This corresponds to a sub-interface of AbstractionImpl
Each SpecializedAbstractionImpl interface corresponds
to a SpecializedAbstraction class
Each SpecializedAbstractionImpl interface declares
methods for the low-level operations needed for an
implementation of that class.
12
Solution(5/7)
Impl1, Impl2
These classes implement the AbstractionImpl interface
These classes provide different implementations for
the Abstraction class.
SpecializedImpl1, SpecializedImpl2
These classes implement one of the
SpecializedAbstractionImpl interfaces and provide
different implementations for a SpecializedAbstraction
class.
13
Consequences
Keeping classes that represent an abstraction
independent of the classes that supply an
implementation for the abstraction
The abstraction and its implementations are
organized into separate class hierarchies
multiple implementation classes for an
abstraction class or multiple abstraction classes
using the same implementation class.
14
Java API Usage
The Java API includes the package java.awt
This package contains the Component class
The Component class is an abstract class that encapsulates
logic common to all GUI components
The Component class has subclasses such as Button, List,
and TextField that encapsulate the logic for those GUI
components that is platform independent
The package java.awt.peer
ComponentPeer, ButtonPeer, ListPeer, and TextFieldPeer
It provides platform-specific support for the subclasses of the
Component class.
15
Code Example - class SimpleSensor
public class SimpleSensor {
private SimpleSensorImpl impl;
SimpleSensor(SimpleSensorImpl impl) {
this.impl = impl;
} // constructor(SimpleSensorImpl)
protected SimpleSensorImpl getImpl() {
return impl;
} // getImpl()
public int getValue() throws SensorException {
return impl.getValue();
} // getValue()
} // class SimpleSensor
16
Code Example - interface SimpleSensorImpl
interface SimpleSensorImpl {
public int getValue() throws SensorException;
} // interface SimpleSensorImpl
17
Code Example - class AveragingSensor
public class AveragingSensor extends SimpleSensor {
AveragingSensor(AveragingSensorImpl impl) {
super(impl);
} // constructor(AveragingSensorImpl)
public void beginAverage() throws SensorException {
((AveragingSensorImpl)getImpl()).beginAverage();
} // beginAverage()
} // class AveragingSensor
18
Code Example - interface AveragingSensorImpl
interface AveragingSensorImpl extends SimpleSensorImpl {
public void beginAverage() throws SensorException;
} // interface AveragingSensorImpl
19
Code Example - class StreamingSensor(1/2)
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.Vector;
public class StreamingSensor extends SimpleSensor implements
StreamingSensorListener, Runnable {
private DataInputStream consumer;
private DataOutputStream producer;
private Vector listeners = new Vector(); // aggregate listeners here
StreamingSensor(StreamingSensorImpl impl) throws
SensorException {
super(impl);
PipedInputStream pipedInput = new
PipedInputStream();
consumer = new DataInputStream(pipedInput);
PipedOutputStream pipedOutput;
try {
pipedOutput = new PipedOutputStream(pipedInput);
} catch (IOException e) {
throw new SensorException("pipe creation failed");
} // try
producer = new DataOutputStream(pipedOutput);
new Thread(this).start();
} // constructor(StreamingSensorImpl)
//...
public void setSamplingFrequency(int freq) throws
SensorException {
((StreamingSensorImpl)getImpl()).setSamplingFrequen
cy(freq);
} // setSamplingFrequency(int)
public void processMeasurement(int value) {
try {
producer.writeInt(value);
} catch (IOException e) {
} // try
} // processMeasurement(int)
public void
addStreamingSensorListener(StreamingSensorListener
listener) {
listeners.addElement(listener);
} // addStreamingSensorListener(StreamingSensorListener)
public void
removeStreamingSensorListener(StreamingSensorListe
ner listener) {
listeners.removeElement(listener);
20
} // addStreamingSensorListener(StreamingSensorListener)
Code Example - class StreamingSensor(5/5)
public void run() {
while (true) {
int value;
try {
value = consumer.readInt();
} catch (IOException e) {
// Pipes is broken so return from this method letting
// ths trhead die.
return;
} // try
for (int i=0; i < listeners.size(); i++) {
StreamingSensorListener listener;
listener
= (StreamingSensorListener)listeners.elementAt(i);
listener.processMeasurement(value);
} // for
} // while
} // run()
} // class StreamingSensor
21
Code Example - interface StreamingSensorImpl
interface StreamingSensorImpl extends SimpleSensorImpl {
public void setSamplingFrequency(int freq) throws SensorException;
public void setStreamingSensorListener(StreamingSensorListener
listener);
} // interface StreamingSensorImpl
22
Related Pattern
Layered Architecture.
The Bridge design pattern is a way of organizing the
entities identified using the Layered Architecture
pattern (described in [BMRSS96]) into classes.
Abstract Factory.
The Abstract Factory pattern can be used by the
Bridge pattern to decide which implementation class to
instantiate for an abstraction object.
Decorator.
The Decorator pattern can be used to dynamically
select the implementation object that an abstraction
object delegates an operation to.
23