Unit 23 Bridge Summary prepared by Kirk Scott 1. Design Patterns in Java Chapter 6 Bridge Summary...

Post on 26-Dec-2015

215 views 0 download

Tags:

Transcript of Unit 23 Bridge Summary prepared by Kirk Scott 1. Design Patterns in Java Chapter 6 Bridge Summary...

1

Unit 23Bridge

Summary prepared by Kirk Scott

2

Design Patterns in JavaChapter 6

Bridge

Summary prepared by Kirk Scott

3

Bridge

• The Bridge design pattern, like many others, is based on identifying abstraction in an application

• When the abstraction is identified, it is factored out and implemented separately

• In other words, the design pattern leads to an abstract class or more likely, a Java interface

4

• When you see a UML diagram of a set of classes which implement the Bridge design pattern, you will note the following– It consists of more than just implementing an abstract class

at the top of a hierarchy– It consists of more than just designing an interface and

implementing the interface in various classes• The design pattern is structurally more clever than that• It has the effect of eliminating unnecessary duplication

in the implementation code

5

• The Bridge design pattern is also known as the Driver pattern

• This terminology arises in the context of database drivers

• It also arises in the context of printers and other computer devices, for example

• The term bridge is descriptive of how the structure of the pattern looks in UML

• That term driver is descriptive of the functionality of the pattern in an application context

6

Bridge

• Book definintion: The intent of the Bridge pattern is to decouple an abstraction from the implementation of its abstract operations, so that the abstraction and its implementation can vary independently.

• Comment mode on:• I don’t find this statement very helpful• I don’t think the idea becomes clear until an

example has been developed

7

An Ordinary Abstraction: On the Way to Bridge

• The book reviews the general ideas of abstraction in class and hierarchy design as a basis for taking up the Bridge pattern

• The UML diagram on the following overhead shows two different machine controllers for two different kinds of machines

8

9

• The controller classes have some methods that probably have the same functionality even though they have different names

• The usual explanation of the difference in method names applies

• The classes come from different sources• For example, the machines may be made by different

manufacturers which supply some of the software needed to integrate the machines into an automated production system

• For this reason, the implementations of the given classes can’t be changed

10

• If possible, it would probably be both conceptually and practically desirable to create an abstract superclass for the machine controller classes

• The superclass would potentially contain constructors and some concrete methods that the subclasses could inherit

• It would also contain abstract declarations of common methods which the subclasses would implement

• However, if the class implementations can’t be changed, building a hierarchy above them in this way can’t be done

11

• Challenge 6.1• State how you could apply a design pattern to allow

controlling various machines with a common interface

• Comment mode on:• This challenge stems immediately from the

foregoing observation about the classes• The question is, how do you abstract out a common

interface when you can’t change the classes themselves?

12

• Solution 6.1• To control various machines with a common

interface, you can apply the Adapter pattern, creating an adapter class for each controller. Each adapter class can translate the standard interface calls into calls that existing controllers support.

13

• Comment mode on:• Although the book didn’t state this in advance,

it becomes apparent that the Bridge pattern is building on the Adapter pattern

• The UML diagram on the following overhead shows the current state of development of the introductory scenario

• It is followed by commentary

14

15

• At the upper left, the abstract MachineManager class defines the common interface, ultimately for controllers

• The MachineManager class has abstract methods as well as one concrete method

• The MachineManager class doesn’t connect directly with the manager classes

16

• At the bottom of the design are two other new classes, FuserManager and StarPressManager

• These classes are subclasses of MachineManager

• These classes have a reference to a FuserController object and a StarPressController object, respectively

17

• What the UML diagram shows is two occurrences of the Object adapter design pattern

• There have to be two new classes, FuserManager and StarPressManager, and two occurrences of the Adapter design pattern

• This is because each of those new classes adapts one of the two different, distinct controller objects

18

• Challenge 6.2• Write a shutdown() method that will stop

processing for the MachineManager class, discharge the bin that was in process, and stop the machine

• As usual, the answer isn’t that difficult, but without problem domain knowledge it’s difficult to predict what it will be

19

• Solution 6.2• public void shutdown()• {• stopProcess();• conveyOut();• stopMachine();• }

20

• Comment mode on:• The code illustrates the technique shown in the chapter

on composites• It is possible to implement a concrete method in the

abstract superclass that calls abstract methods in the superclass

• These calls to abstract methods in the superclass rely on the implementations of the methods in the subclasses

• The implementations of the methods in the subclasses ultimately rely on the methods in the adapted objects

21

From Abstraction to Bridge

• The collection of classes introduced so far is based on a MachineManager class and subclasses FuserManager and StarPressManager

• In other words, there is a hierarchy based on different kinds of machines

• Suppose you want to introduce a new kind of concept, that of a machine manager that includes a handshaking functionality

• Handshaking refers to the idea of passing status messages back and forth

22

• In addition to handshaking machine managers, you’d like to keep the old, non-handshaking machine managers

• Let handshaking be abbreviated Hsk in class names

• The following UML diagram illustrates the new class hierarchy

23

24

• Before going any further with the book’s explanation, notice that a picture like this came up in CS 202

• The idea was that there was an inheritance hierarchy of foods, and you also wanted to implement the concept of taxability

• Since Java doesn’t support multiple inheritance, taxability was done with an interface

• The following UML diagram illustrated this in CS 202

25

FoodV5

PackagedFoodV5 BulkFoodV5

TaxedPackagedFoodV5 TaxedBulkFoodV5

«interface»Taxable Interface

26

• The book’s example and the CS 202 example are analogous in structure

• The only difference is that the CS 202 example explicitly identifies an interface

• The thing that should strike you at this point is that something is wrong

• Namely, how come, when implementing an interface, every subclass in the inheritance hierarchy has to have a new subclass?

27

• According to the object-orientation brainwashing, using object-oriented concepts like inheritance, you shouldn’t have to re-implement common things

• But in this case, every taxable subclass, or in the book’s example, every handshaking manager class, will have to implement taxability/handshaking

• Even though the subclasses are different, it is highly likely that for many of the subclasses, the implementing code will be largely the same

28

• The book’s UML diagram is shown again below for reference

29

30

• The book’s diagram shows a setTimeout(:double) method in both HskFuserManager and HskStarPressManager

• The book points out that this is a good example of a method which may be exactly the same in both

• It can’t be pushed up higher in the hierarchy because the superclasses of Hsk classes are non-handshaking classes without this characteristic

31

• As noted in reference to the CS 202 code, abstracting setTimeout() into an interface also doesn’t solve the problem, because interfaces don’t contain implementations

• If the number of subclasses increases, two practical problems result

32

• 1. You have to write duplicate code x times• This is not too bad because you can just copy and

paste• 2. If the design and implementation change in the

future, you have to remember that there were x places with common code and change each of them

• Copy and paste helps with the mechanics, but keeping track of where repetition occurs in designs is not pleasant

33

• The book takes the approach of trying to describe in words how the Bridge pattern can solve this problem

• It then goes through some UML diagrams illustrating it

• I think it is easier to understand by looking at the UML diagrams first and then wading through the words

34

• The book does the UML diagrams as challenges• The explanation of the first UML diagram is that it

shows the overall structure of the Bridge pattern, while teasing you about what the components of it are

• This can be skipped over quickly so that you can see the complete solution

• Then work backwards trying to understand in words what was done

• The incomplete UML diagram is shown on the following overhead

35

36

• Challenge 6.3• Figure 6.4 shows the MachineManager

hierarchy refactored into a bridge. Fill in the missing labels.

37

• Before showing the solution, on the following overhead the starting point is shown again

• In other words, this is what you’ve got, which is undesirable

38

39

• Solution 6.4• Figure B.5 shows a solution• In other words, this is the redesign using the

Bridge pattern

40

41

• There is much to explain here, and many different ways to go about it

• Overall, structurally, simplistically, you can refer to the left hand side and the right hand side of the diagram

• Of course, these designations are arbitrary, but we will take them as shown in the solution UML

42

• On the left hand side, the MachineManager2 class remains as a superclass (the 2 is just a version number, indicating that this is the MachineManager class in the solution

• A hierarchy grows underneath it, but it’s not a hierarchy of different machine manager classes for different kinds of machines

• It is a simple hierarchy with one subclass, the machine manager subclass with handshaking, HskMachineManager2 (with version number)

43

• The book’s example never introduced the idea of an interface, but my example did

• It is worth noting that the concept that was captured as an interface in my example becomes a superclass/subclass relationship in the solution

• It is also worth noting that the MachineManager2 class differs from the MachineManager class because it has a reference to something which implements the new interface which appears in this design, the MachineDriver interface

44

• The MachineDriver interface appears at the top of the right hand side of the diagram

• Before going further, note that its name contains the word “driver”

• Presumably it could also have been named MachineBridge

45

• The underlying idea is that the MachineDriver interface ultimately makes it possible for the MachineManager2 class to make use of instances of any kind of machine

• Visually, the MachineDriver class itself is the bridge between the manager hierarchy and the machines

• It is important to note, once again, that the link to the bridge is with a single, open-headed arrow—the manager has a reference to something that implements the interface

• For me, the arrow to the MachineDriver class is the reminder that a bridge is coming in the design

46

• Continuing to consider the MachineDriver interface:

• It contains method definitions that are common to machines

• Underneath it in the diagram are classes named FuserDriver and StartPressDriver that implement the MachineDriver interface

47

• Again, there is a bit of a turn-about from the original design

• The original design had an inheritance hierarchy based on machine manager type

• In the new design the abstractions corresponding to different kinds of machines don’t appear in an inheritance hierarchy

• Instead, the different machine drivers, those abstractions which represent different machines, implement a common interface

48

• Returning to how the overall structure works:• An instance of plain MachineManager2 doesn’t

have handshaking• It is a manager of a fuser, for example, by virtue

of the fact that it has a reference to an object of FuserDriver, which implements the MachineDriver interface

• The same kind of explanation applies if it’s a manager of a StarPress

49

• Now observe that it works the same way for HskMachineManager2

• The reference arrow only appears between MachineManager2 and MachineDriver

• However, HskMachineManager2 is a subclass of MachineManager2

• Therefore, it also has a reference to MachineDriver

50

• Therefore, an instance of HskMachineManager2, the kind of manager that has handshaking, manages a certain kind of machine by virtue of the specific kind of driver it has a reference to

• Look at the UML diagram again and then consider the additional comments that follow it

51

52

• In general, the pattern is based on a decoupling of managers and machines

• The idea is that the left hand side, the hierarchy based on machine manager types, can grow and change

• The right hand side, based on machine types, can grow and change

• They can grow and change independently• Changes on one side don’t require (multiple)

changes on the other

53

• More specifically, what you observe is a decoupling between the abstraction of a machine manager and the implementation of its abstract methods

• In the original design the MachineManager class was abstract and contained abstract methods

• In the new design, the MachineManager2 class, although not declared abstract, is generically a kind of abstraction, as is any superclass in a hierarchy

54

• The key point is this:• All of the abstract methods that had been in

MachineManager no longer exist in MachineManager2

• The declarations of all of those methods have been moved to the MachineDriver interface

• The bridge, or driver is the interface where all of the abstract methods are moved to

• This is how the separation, or decoupling of the pattern is accomplished

55

• The explanation for this is not mysterious• In the original design the machine manager sat above a

hierarchy of classes that concretely implemented the abstraction of different kinds of machines

• The machines have moved to the right hand side of the design, so the methods associated with them can be moved to the interface above them

• All that remains in the machine manager are methods intrinsic to management—and these can be inherited by the handshaking subclass, which is also contains purely management code

56

• Moving the abstract, machine management methods which are machine specific out of the machine manager class and into the machine driver interface has two results:

• The machine management hierarchy can grow based solely on machine management characteristics like handshaking

• The driver/machine ‘hierarchy’ can grow to an arbitrary number of different kinds of machines

57

Defining the Term Driver More Specifically

• Observe again that an instance of MachineManager2 has a reference to an object of the type MachineDriver

• The MachineDriver interface is designed for the use of the machine manager

• The book expresses the relationship in this way:• The concrete driver classes that implement the

driver interface adapt manager to requests to specific kinds of machines

58

• It is these concrete classes like FuserDriver and StarPressDriver that are the actual drivers

• Finally, this is the book definition of a driver:• A driver is an object that operates a computer

system or an external device according to a well-specified interface.

• The book also makes this statement, which explains the relationship between a bridge and a driver:

• Drivers provide the most common example of the Bridge pattern in practice.

59

Drivers as Bridges

• Look at the UML diagram of the new design for the nth time

60

61

• The book states that each driver is an instance of the Adapter pattern

• Consider the right hand side of the diagram• It corresponds to the left hand side of the UML

diagram for the Class Adapter design pattern• Each concrete machine driver class implements

the machine driver interface, adapting a particular kind of machine to a client

• The client in this case is a machine manager

62

• If you want to be picky, notice that the definition of a driver has nothing to with developing the inheritance hierarchy on the left hand side of the new design

• The left hand side of the design is simply client code, the bridge class is an adapter, and all that’s missing from the picture are the machine classes which the drivers adapt to

• In other words, a driver is a bridge due to its intent• Structurally, a driver is an application of the idea of

adaptation presented earlier

63

• This view of bridges/drivers leads to some higher level observations about object-oriented design of software systems

• Restating at a higher level the idea of decoupling which was raised earlier:

• This design separates application development (what happens on the machine manager side) from the development of the specific machine drivers

• This is a consequence of having introduced an interface into the design

• The implicit development order here is interface first, drivers second

64

• You can also view this from the opposite perspective:• You decide that the design is to be based on drivers• Then it becomes necessary to develop an abstract model

(interface) for the machine(s)/system(s) to be driven• Then in theory, the client (the manager) can do anything

it wants to to any machine through this common interface

• The development order here is the concept of drivers first, then develop the common interface, then implement the drivers to the interface specifications

65

A Limitation to this Approach

• The limitation of the bridge/driver approach has to do with the design of hierarchies and interfaces in general, and is not specifically related to bridges

• When the common interface is designed, the idea is that every method in the interface applies to each machine that implements it

66

• However, by definition, machines differ from each other and each one may have unique methods of its own

• If those methods are not in common, they may not be put into the interface

• As a result, individual machines will have capabilities that a client, a machine manager, can’t control through calls to methods in the interface, because the methods aren’t in the shared interface

67

• There are two approaches to solving this problem

• 1. Write special case code in the machine manager

• This code would have to check whether an object was an instance of a given class before calling on it a unique method belonging only to that class

68

• 2. Go ahead and put even unique methods into the common interface

• Then in the real driver classes, include only dummy implementations of those methods for the classes that they don’t apply to

• This eliminates the need for checking code in the client

• It does imply that the client code needs to be written under the assumption that for some method calls ‘nothing may happen’

69

Database Drivers

• An everyday example of the use of drivers in software arises in the database world

• You may have seen the acronyms ODBC and JDBC

• They stand for open database connectivity and Java database connectivity

• They are standards that make it possible to mount and use different database systems in a given computer environment

70

• JDBC can be briefly described as an application programming interface for running SQL statements

• The key word in the previous statement is ‘interface’

• The API defines a set of valid database calls that an application program can execute

71

• A JDBC compliant dbms driver implements the interface and supports the calls

• There is a separate driver for each different dbms that is supported

• These drivers adapt the interface method call to the native call in that dbms that supports it

72

• The previous discussion was conducted as if the client is a single class, there is one driver/adapter, and one underlying “thing” that is adapted to

• Of course, reality can be more complex• Obviously, complexity on the application side

is the application programmer’s concern

73

• Note that in the db world, drivers are things that are givens, and the application programmer either uses them or not, but doesn’t develop them

• If they are complex, that is the problem of the organization that produced the drivers

• The JDBC driver implementation may adapt to more than one class, for example

• All the application programmer has to worry about is a single instance of the driver and the interface for making calls to it

• The diagram on the following overhead gives a simple overview of the situation

74

75

The End?

• The rest of the chapter continues the topic of JDBC database drivers

• If there is time, it will be covered in class• Otherwise, it will be up to students to read the

sections in the book and the remainder of these overheads on their own

76

• The book continues the JDBC discussion with some example code

• In effect what you will see is an example of how to embed SQL access to a database into a Java program

• The book summarizes the use of a JDBC driver in this way:

• You load it, connect to a database, and create a Statement object

77

• Here is the code for those steps:• Class.forName(driverName);• Connection c = DriverManager.getConnection(url, user, pwd);• Statement stmt = c.createStatement();

78

• In the API for a Statement object there is a method executeQuery() that accepts an SQL query as a parameter

• This method returns something typed as a ResultSet

• The ResultSet may contain multiple table rows• Like one of the Java Collection classes, it is

possible to iterate over the ResultSet, acquiring the data values from one row at a time

79

• Here is the code for those steps:• ResultSet result =

stmt.executeQuery(“SELECT name, apogee FROM firework”);

• while(result.next())• {• String name = result.getString(“name”);• int apogee = result.getInt(“apogee”);• System.out.println(name + “, “ +

apogee);• }

80

• Next, the book shows an incomplete UML sequence diagram based on the code example

• This is given on the next overhead• It will be followed by a challenge

81

82

• Challenge 6.4• Figure 6.5 shows a UML sequence diagram

that illustrates the message flow in a typical JDBC application. Fill in the missing type names and the missing message name in this illustration.

83

Solution 6.4

84

• Challenge 6.5• Suppose that at Oozinoz, we currently have only SQL

Server databases. Provide an argument that we should use readers and adapters that are specific to SQL Server. Provide another argument that we should not do this.

• Comment mode on:• What they are struggling to ask here is whether it makes

sense to rely on the existing, commercially available database driver interfaces, or whether it makes sense to simply code to the native standard for SQL Server

85

• Solution 6.5• Two arguments in favor of writing code specific to SQL

server are as follows.• 1. We can’t predict the future, so spending money now

to prepare for eventualities that may never occur is a classic mistake. We have SQL Server now, and more speed means better response times, which is money in the bank today.

• 2. By committing to SQL Server, we can use every feature available in the database, without worrying whether other database drivers support it.

86

• Two arguments in favor of using the generic SQL drivers are as follows.

• 1. If we use generic SQL objects to write our code, it will be easier to modify it if we ever change database providers and start using, say, Oracle. By locking the code into SQL Server, we diminish our ability to benefit from the competitive database market.

• 2. Using generic drivers will let us write experimental code that runs against inexpensive databases, such as MySQL, without relying on a test SQL Server database.

87

Summary

• The Bridge pattern ultimately results from abstraction in a design and a need to ‘factor’ in more than one way

• Given an abstract class (with abstract methods) the time may come when you would like to extend it in an orthogonal hierarchy

• Java doesn’t support multiple inheritance, so that is not directly possible

88

• The Bridge pattern means that the abstract methods are moved into an interface

• There can be more than one class that implements the interface

• These classes would have been subclasses of the original class in the old design

• In the new design, the original class then makes use of an object that implements the interface

• In the new design, the new hierarchy can be implemented as subclasses of the original class

89

• Specifically, the abstraction and its implementation have been decoupled

• More generally, it’s clear that there can be an unlimited number of classes that implement the new interface

• Plus, the new hierarchy can grow as needed• Subclasses of the new hierarchy will be able to use

objects that implement the interface• This is because the subclasses will inherit the reference

to such objects from the original class, which now has a reference added to it

90

• The end result of all this is not having to duplicate method code because one hierarchy is laid over another

• On the other hand, you also have to deal with the problem of methods that are unique to individual classes that implement the hierarchy

• Should they be left out of the interface?• Or does it make sense to include them in the hierarchy

even though some or most of the implementing classes will have to provide bogus implementations of those methods?

91

• Drivers are the most common example of the application of the Bridge pattern

• Database drivers provide a good software example of drivers

• Database drivers illustrate the trade-off between using drivers and not using drivers

• Drivers give you flexibility and generality• Drivers may not support methods that are

unique to a given database

92

• Not using drivers means writing code specific to a given database

• On the one hand, this may mean being able to use unique features and getting good performance

• On the other hand, it locks your software into that specific database

• It is not always clear which choice is better, but it is important to be aware of the trade-off when making the choice

93

The End