UNIT-3 Structural Patterns: Intent
UNIT-3 Structural Patterns: Intent
UNIT-3 Structural Patterns: Intent
Structural Patterns
Introduction:
Structural patterns are concerned with how classes and objects are composed to form
larger structures.
Structural class patterns use inheritance to compose interfaces or implementations.
Example: The class form of the Adapter pattern.
In general, an adapter makes one interface (the adaptee's) conform to another,
thereby providing a uniform abstraction of different interfaces.
A class adapter accomplishes this by inheriting privately from an adaptee class.
The adapter then expresses its interface in terms of the adaptee's.
Rather than composing interfaces or implementations, structural object patterns
describe ways to compose objects to realize new functionality.
The object composition becomes flexible due to the ability to change the composition at
run-time, which is impossible with static class composition.
Example: Composite pattern.
How to build a class hierarchy made up of classes for two kinds of objects:
primitive and composite.
The composite objects let you compose primitive and other composite objects into
arbitrarily complex structures.
3.1Adapter:
Intent:
Convert the interface of a class into another interface clients expect. Adapter lets classes
work together that couldn't otherwise because of incompatible interfaces.
Also Known As: Wrapper
Motivation:
Sometimes a toolkit class that's designed for reuse isn't reusable only because its
interface doesn't match the domain-specific interface an application requires.
Consider for example a drawing editor that lets users draw and arrange graphical
elements (lines, polygons, text, etc.) into pictures and diagrams.
Applicability:
Use the Adapter pattern when
you want to use an existing class, and its interface does not match the one you need.
you want to create a reusable class that cooperates with unrelated or unforeseen classes,
that is, classes that don't necessarily have compatible interfaces.
(object adapter only) you need to use several existing subclasses, but it's impractical to
adapt their interface by subclassing every one. An object adapter can adapt the
interface of its parent class.
Object adapter
Participants:
Target (Shape)
defines the domain-specific interface that Client uses.
Client (DrawingEditor)
collaborates with objects conforming to the Target interface.
Adaptee (TextView)
defines an existing interface that needs adapting.
Adapter (TextShape)
Implementation:
Here are some issues to keep in mind while implementing Adapter:
1. Implementing class adapters in C++. Adapter would inherit publicly from Target and
privately from Adaptee.
2. Pluggable adapters.
Participants:
Abstraction (Window)
defines the abstraction's interface.
maintains a reference to an object of type Implementor.
RefinedAbstraction (IconWindow)
Extends the interface defined by Abstraction.
Implementor (WindowImp)
defines the interface for implementation classes. Typically the Implementor
interface provides only primitive operations, and Abstraction defines higher-
level operations based on these primitives.
ConcreteImplementor (XWindowImp, PMWindowImp)
implements the Implementor interface and defines its concrete implementation.
Collaborations:
Abstraction forwards client requests to its Implementor object.
Consequences:
The Bridge pattern has the following consequences:
1. Decoupling interface and implementation.
Decoupling Abstraction and Implementor also eliminates compile-time
dependencies on the implementation.
Implementation:
Consider the following implementation issues when applying the Bridge pattern:
1. Only one Implementor.
Useful when a change in the implementation of a class must not affect its existing
clients
2. Creating the right Implementor object.
How, when, and where do you decide which Implementor class to instantiate
when there's more than one?
3. Sharing implementors.
4. Using multiple inheritance.
Sample Code:
class Window {
public:
Window(View* contents);
// requests handled by window
virtual void DrawContents();
virtual void Open();
virtual void Close();
virtual void Iconify();
virtual void Deiconify();
// requests forwarded to implementation
virtual void SetOrigin(const Point& at);
virtual void SetExtent(const Point& extent);
virtual void Raise();
virtual void Lower();
3.3 Composite:
Intent:
Compose objects into tree structures to represent part-whole hierarchies. Composite lets
clients treat individual objects and compositions of objects uniformly.
Motivation:
Graphics applications like drawing editors and schematic capture systems let users
build complex diagrams out of simple components.
Applicability:
Use the Composite pattern when
you want to represent part-whole hierarchies of objects.
you want clients to be able to ignore the difference between compositions of
objects and individual objects. Clients will treat all objects in the composite
structure uniformly.
Structure:
Participants:
Component (Graphic)
declares the interface for objects in the composition.
implements default behavior for the interface common to all classes, as
appropriate.
declares an interface for accessing and managing its child components.
(optional) defines an interface for accessing a component's parent in the
recursive structure, and implements it if that's appropriate.
Leaf (Rectangle, Line, Text, etc.)
represents leaf objects in the composition. A leaf has no children.
defines behavior for primitive objects in the composition.
Composite (Picture)
defines behavior for components having children.
stores child components.
implements child-related operations in the Component interface.
Client
manipulates objects in the composition through the Component interface.
Collaborations:
Clients use the Component class interface to interact with objects in the
composite structure. If the recipient is a Leaf, then the request is handled
directly. If the recipient is a Composite, then it usually forwards requests to its
child components, possibly performing additional operations before and/or after
forwarding.
Implementation:
There are many issues to consider when implementing the Composite pattern:
Explicit parent references.
Sharing components.
Maximizing the Component interface.
Declaring the child management operations.
The decision involves a trade-off between safety and transparency:
Defining the child management interface at the root of the class hierarchy gives
you transparency.
Defining child management in the Composite class gives you safety.
Should Component implement a list of Components?
Child ordering.
Caching to improve performance.
Who should delete components?
What's the best data structure for storing components? The choice of data structure
depends on efficiency.
Sample Code:
class Equipment {
public:
virtual ~Equipment();
Currency CompositeEquipment::NetPrice () {
Iterator* i = CreateIterator();
Currency total = 0;
for (i->First(); !i->IsDone(); i->Next()) {
total += i->CurrentItem()->NetPrice();
}
delete i;
return total;
}
Known Uses:
The original View class of Smalltalk Model/View/Controller was a Composite, and
nearly every user interface toolkit or framework has followed in its steps, including
ET++ and InterViews, Graphics, and Glyphs.
The RTL Smalltalk compiler framework uses the Composite pattern extensively.
Another example of this pattern occurs in the financial domain, where a portfolio
aggregates individual assets.
The Command pattern describes how Command objects can be composed and
sequenced with a MacroCommand Composite class.
Related Patterns:
Often the component-parent link is used for a Chain of Responsibility.
Decorator is often used with Composite.
Flyweight lets you share components, but they can no longer refer to their parents.
Iterator can be used to traverse composites.
Visitor localizes operations and behavior that would otherwise be distributed across
Composite and Leaf classes.