Handle-Body
Inheritance hierarchies can be hierarchies of concepts or hierarchies of implementations. For example:
Mixing concepts with implementations can lead to hierarchies that are confusing and difficult to maintain.
Create two hierarchies: a conceptual hierarch and a hierarchy of implementations. The base of the implementation hierarchy is an Implementer interface. Use delegation to connect the two hierarchies:
Assume we want to define a portable GUI library. Our conceptual hierarchy might use the Composite Pattern to define a conceptual hierarchy of GUI components:
The draw() methods in the subclasses call upon protected utility methods inherited from the component base class:
class Button: public Component
{
private:
string label;
public:
void draw()
{
drawRectangle();
drawText(xc, yc, label);
}
};
The protected utility methods in the Component base class delegate to a private peer that implements a utility interface:
Here's the interface:
class ComponentImplementer
{
public:
virtual void drawRectangle(int xc, int
yc, int h, int w) = 0;
virtual void drawText(int xc, int yc,
string text) = 0;
};
Here's the complete code for the conceptual Component base class:
class Component
{
private:
ComponentImplementer* peer;
protected:
int height, width;
int xc, yc; // co-ordinates of upper
left corner
ComponentImplementer* getPeer() {
return peer; }
void setPeer(ComponentImplementer*
peer)
{
this->peer = peer;
}
// some utilities:
void drawRectangle()
{
peer->drawRectangle(xc, yc,
height, width);
}
void drawText(int xc, int yc, string
text)
{
peer->drawText(xc, yc, text);
}
public:
Component(ComponentImplementer* peer =
0)
{
xc = yc = 0;
height = width = 150;
this->peer = peer;
}
virtual void draw() = 0;
};
Suppose X-Kit and Y-Lib are two libraries for creating platform-dependent GUIs. For each library we will need to provide an implementation of the Implementer interface. This can be regarded as a special case of the Adapter Pattern:
class XComponent: public
ComponentImplementer
{
public:
void drawRectangle(int xc, int yc, int
h, int w)
{
// X-kit specific code goes here
}
void drawText(int xc, int yc, string
text)
{
// X-kit specific code goes here
}
};
Concept = JDBC Statement
ConceptA = JDBC PreparedStatement
Implementor = Driver
ImplementationX = ODBCBridge
ImplementationY = OracleDriver
Java uses the JDBC API for interacting with relational database systems. The application first uses a driver manager to register all available database drivers on the local machine. The manager asks each registered driver to start a session (Connection) with the database specified by the application. Once a session begins, the application uses a Statement object to query the database.
There are several types of drivers:
Concept = Shape
ConceptA = Circle
Implementor = GC
ImplementationX = PoorMansGC
ImplementationY = OpenGL adapter
Concept = GUI Component
ConceptA = Button
Implementor = IComponent
ImplementationX = XWindowsComponentAdapter
ImplementationY = MSWindowsComponentAdapter
Concept = AbstractPlatform
ConceptA =
Implementor = PlatformInterface
ImplementationX = UnixPlatformAdapter
ImplementationY = WindowsPlatformAdapter
Concept
ConceptA
Implementor
ImplementationX
ImplementationY
Concept = Deque
ConceptA = Stack or Queue
Implementor = List
ImplementationX = LinkedList
ImplementationY = ArrayList