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