INFO3220: Object Oriented Design
20
18
S1INFO3220: Object Oriented Design
Bernhard Scholz
Bernhard.Scholz@sydney.edu.au
School of Information Technologies, University of Sydney
Semester 1, 2018
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 1 / 62
20
18
S1Copyright WarningCOMMONWEALTH OF AUSTRALIACopyright Regulations 1969WARNING
This material has been reproduced and communicated to you by or on
behalf of the University of Sydney pursuant to Part VB of the Copyright Act
1968 (the Act).
The material in this communication may be subject to copyright under the
Act. Any further copying or communication of this material by you may be
the subject of copyright protection under the Act.
Do not remove this notice.
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 2 / 62
20
18
S1
1 Lecture 14: Abstracting away tight coupling
Bridge
Composite
Proxy
2 Lecture 15: Associative Containers and STL Algorithms
Associative Containers
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 3 / 62
20
18
S1Topic 14: Abstracting away tight coupling
The Bridge, Composite and Proxy
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 3 / 62
20
18
S1The Bridge Design Pattern
separating responsibilities into different classes
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 4 / 62
20
18
S1Design Pattern: BridgePurpose/Intent: Decouple an abstraction from its implementation so thetwo can vary independentlyMotivation: The usual way to have multiple implementations of aninterface is inheritance, but this is sometimes not flexible
enough
Applicability: Use this pattern when you want to decouple the binding
between interface and implementation, when both should be
extensible through inheritance, when changes in the
implementation should have no impact on clients
Benefits: Much better decoupling and flexibility, better extensibility,
and implementation is hidden from clients
Limitations: Has to be constructed up front
See Also: Abstract Factory (to create and configure a Bridge), Adapter
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 5 / 62
20
18
S1ExampleSuppose you have a Window abstraction that permits you to displaywindows on multiple platforms: you might then subclass it withPhoneWindow and PCWindow.
Window
PCWindow PhoneWindow
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 6 / 62
20
18
S1Example (cont.)Suppose you then have a subclass of Window that permits a fancy display,e.g. extra with icons: IconWindow.In this situation you’d have to implement subclasses of IconWindow forboth PCWindow and PhoneWindow:
Window
PCWindow PhoneWindow IconWindow
PCIconWindow PhoneIconWindow
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 7 / 62
20
18
S1Example (cont.)The Bridge gets around this by separating the abstract and concretehierarchies. In the above case we might end up with something more likethis:
bridgeDrawText()DrawRect()
Window
DeviceDrawText()
DeviceDrawLine()
WindowImplementation
imp->DeviceDrawLine()
imp->DeviceDrawLine()
imp->DeviceDrawLine()
imp->DeviceDrawLine()
DrawBorder()
IconWindow
DrawCloseBox()
TransientWindow
DrawRect()
DrawText()
DrawRect()
DeviceDrawText()
DeviceDrawLine()
PhoneWindowImp
DeviceDrawText()
DeviceDrawLine()
PCWindowImp
PhoneDrawLine()
PhoneDrawString()
implementation
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 8 / 62
20
18
S1Example
In this example all operations on Window subclasses are implemented in
terms of abstract operations from the WindowImplementation interface.
This separates / decouples the window abstractions from the
platform-specific implementations, so we can vary the two independently.
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 9 / 62
20
18
S1Structure
Operation()
Abstraction
RefinedAbstraction
OperationImp()
ConcreteImplementorA
OperationImp()
Implementor
imp->OperatorImp()
OperationImp()
ConcreteImplementorB
imp
Client
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 10 / 62
20
18
S1Participants Operation()Abstraction
RefinedAbstraction
OperationImp()
ConcreteImplementorA
OperationImp()
Implementor
imp->OperatorImp()
OperationImp()
ConcreteImplementorB
imp
Client
Abstraction defines the abstraction’s interface and maintains a reference
to an object of type Implementor.
Refined Abstraction extends the Abstraction classes interface.
Implementor defines the interface for the implementing classes: it can be
quite different from the interface of Abstraction: usually
Implementor’s interface is very primitive and Abstraction has
higher level operations based on these primitives.
ConcreteImplementor implements the Implementor interface and defines
the concrete implementation.
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 11 / 62
20
18
S1ImplementationAlthough in C++ we can use multiple inheritance to combine an interfacewith its implementation, e.g., by inheriting publicly from Abstraction and
privately from ConcreteImplementation, this permanently binds the
implementation to its interface.
This means that you can’t implement a true Bridge with multiple
inheritance in C++.
If there’s only one implementation, then you don’t really need the full
Bridge: the abstract Implementor class isn’t necessary.
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 12 / 62
20
18
S1More implementationIf Abstraction knows about all the ConcreteImplementor clases then it caninstantiate one of them in its constructor and construct different concreteobjects based on input parameters such as getting a list size (sometimes a
linked list is fine).
(Another idea is to change implementation on the fly if the situation
demands it, e.g., if a list gets bigger so a previous implementation is no
longer adequate.)
Alternatively one could delegate such responsibilities to another object like
a Factory to create the correct platform-specific objects.
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 13 / 62
20
18
S1Another exampleIn the previous example we considered a broad use for the application of aBridge which was rather abstract. In the next example we will consider a
more low level implementation of a Bridge so that we can see some code.
Consider the case where we have a base class Shape and a Circle class
which implements Shape. In this example these are the Abstraction and
Concrete Abstraction respectively.
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 14 / 62
20
18
S1Another exampleIn this system we have three approaches to render a shape using differentrendering libraries. Our aim is to take these three approaches and decouple
them from the Shape classes.
To do this we will create three new classes RendererImplementation1,
RendererImplementation2, and RendererImplementation3 which all
implement the Renderer interface. There are our ConcreteImplementers
and our Implementer respectively.
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 15 / 62
20
18
S1The Implementers1 class Renderer2 {3 public :4 virtual void drawCircle ( double x, double y, double radius ) = 0;5 };67 class RendererImplementation1 : public Renderer
8 {
9 public :
10 void drawCircle ( double x, double y, double radius )
11 {
12 std :: cout << " Calling RendererImplementation1 drawCircle function " << std :: endl;
13 }
14 };
15
16 class RendererImplementation2 : public Renderer
17 {
18 public :
19 void drawCircle ( double x, double y, double radius )
20 {
21 std :: cout << " Calling RendererImplementation2 drawCircle function " << std :: endl;
22 }
23 };
24
25 class RendererImplementation3 : public Renderer
26 {
27 public :
28 void drawCircle ( double x, double y, double radius )
29 {
30 std :: cout << " Calling RendererImplementation3 drawCircle function " << std :: endl;
31 }
32 };
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 16 / 62
20
18
S1The Abstractions1 class Shape2 {3 public :4 Shape ( Renderer * renderer ) : m_renderer ( renderer ) {}5 virtual ~ Shape () {};67 virtual void draw () = 0;
8 virtual void resizeShape ( double percentage ) = 0;
9 protected :
10 Renderer * m_renderer ;
11 };
12
13 class Circle : public Shape
14 {
15 public :
16 Circle ( double x, double y, double radius , Renderer * renderer )
17 : Shape ( renderer ), m_xCoordiante (x), m_yCoordiante (y), m_radius ( radius ) {}
18 virtual ~ Circle () { }
19
20 void draw ()
21 {
22 m_renderer -> drawCircle ( m_xCoordiante , m_yCoordiante , m_radius );
23 }
24 void resizeShape ( double percentage )
25 {
26 m_radius *= percentage ;
27 }
28 private :
29 double m_xCoordiante ;
30 double m_yCoordiante ;
31 double m_radius ;
32 };
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 17 / 62
20
18
S1All together1 int main ()2 {3 std :: vector < Shape *> vector ;4 vector . push_back (new Circle (1, 2, 4, RendererFactory :: getRendererImpl1 ()));5 vector . push_back (new Circle (11 , 21, 6, RendererFactory :: getRendererImpl2 ()));6 vector . push_back (new Circle (-1, -2, 3, RendererFactory :: getRendererImpl3 ()));7
8 for ( size_t i = 0; i < vector .size (); ++i)
9 {
10 vector [i]->draw ();
11 // cleaning up
12 delete vector [i];
13 }
14 }
~> g++ BridgeExample.cc -o bridgeExample
~> ./bridgeExample
Calling RendererImplementation1 drawCircle function
Calling RendererImplementation2 drawCircle function
Calling RendererImplementation3 drawCircle function
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 18 / 62
20
18
S1All together1 int main ()2 {3 std :: vector < Shape *> vector ;4 vector . push_back (new Circle (1, 2, 4, RendererFactory :: getRendererImpl1 ()));5 vector . push_back (new Circle (11 , 21, 6, RendererFactory :: getRendererImpl2 ()));6 vector . push_back (new Circle (-1, -2, 3, RendererFactory :: getRendererImpl3 ()));7
8 for ( size_t i = 0; i < vector .size (); ++i)
9 {
10 vector [i]->draw ();
11 // cleaning up
12 delete vector [i];
13 }
14 }
~> g++ BridgeExample.cc -o bridgeExample
~> ./bridgeExample
Calling RendererImplementation1 drawCircle function
Calling RendererImplementation2 drawCircle function
Calling RendererImplementation3 drawCircle function
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 18 / 62
20
18
S1Isn’t a Bridge just a fancy Adapter?The Bridge design pattern has a structure similar to an object Adapter,but Bridge has a different intent. It is meant to separate an interface from
its implementation so that they can be varied easily and independently
while an Adapter aims to change the interface of an existing class.
Therefore, the Bridge works well if we want to extend an existing class,
decoupling the implementation details of a specific feature of the class
from its implementation. The Adapter is more suited if we wish to reuse
an existing class for a new purpose but apply a new (often more relevant)
interface.
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 19 / 62
20
18
S1The Composite Design Pattern
describes groups of objects which should
treated in a common fashion
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 20 / 62
20
18
S1Design Pattern: CompositePurpose/Intent: Compose objects into tree structures, so individualyobjects and compositions of objects can be treated the samewayMotivation: Creating graphical objects that contain other graphical
objects can get unweildy with several levels of more and
more specialised items contained
Applicability: Whenever you want to represent part-whole hierarchies of
objects, and client code to treat objects uniformly
Benefits: A short inheritance hierarchy gives rise to an arbitrarily large
composition hiearchy; client can be very simple
Limitations: Can make the design too general: ease of adding new
components means it’s hard to restrict what components a
composite has, which can’t be constrained using the type
system
See Also: Chain of Responsibility, Decorator, Flyweight, Iterator, Visitor
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 21 / 62
20
18
S1Example
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 22 / 62
20
18
S1ExampleSuppose you’re writing a calculation machine. You need to form arbitraryexpressions like r1,r2 = −b±pb2−4ac2a
Each expression needs to be
evaluable somehow, and the
complete expression can be
evaluated only when all of its
components have been
evaluated.
This is a very common place you
would use the composite design.
The other is in the design of
GUIs.
How would you minimally
transform the composite object
represented by the tree on the
right to get the other root?
In this example the expression tree for r1
would be
Divide
Add
Negate
b
Square Root
MultiplySquare
b
Subtract
Multiply4
a c
Multiply
2 a
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 23 / 62
20
18
S1StructureClient Operation()Add(Component)Remove(Component)GetChild(int)Component
Operation()
Leaf
Operation()
Add(Component)
Remove(Component)
GetChild(int)
Composite
for all g in children
g.Operation()
children
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 24 / 62
20
18
S1ParticipantsComponent declares the interface for objects in the composition, andimplements common behaviour; declares an interface formanaging its children.Leaf has no children, defines behaviour for primitive objects
Composite defines behaviour for components having children and stores
those children, implements the operations defined in
Component;
Client manages the objects in the composition only through the
Component interface.
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 25 / 62
20
18
S1ImplementationSome useful notes on how to implement this:Parent references It’s often useful to navigate back up a composition treeusing references to the parent: these references have to bemaintained as a class invariant though, so should only be
changed when adding a component to a composite.
Sharing components This doesn’t work well with having parent references!
But it’s sometimes useful when you have components that
can be contained in more than one composite item (like ‘b’
above).
Maximizing the Component interface seems a good way to go, to ensure
that the client doesn’t have to care about which component
object is being called, but that doesn’t sit well with the
“don’t implement interface you don’t need” paradigm. A
little creativity is often needed to reconcile these. . .
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 26 / 62
20
18
S1Implementation (cont.)Managing the children is always an issue (trust me); and in this case itmanifests as a conflict between putting the implementationof child management at the base or in the derived classes: ifthey’re in the base, then derived classes might attempt to dothe impossible or meaningless such as adding components to
a leaf; if they’re in the Composite objects only then you lose
transparency as then Leaf and Composite have different
interfaces.
Containment of child objects as a set in a Component takes up space
which you might not want to waste if you have many Leaf
objects.
Ordering may be important: if it is, as with the expression tree
example, then you need to ensure that the ordering is
maintained correctly in whatever containers you use for the
children (e.g., not a set!).
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 27 / 62
20
18
S1Implementation (cont.)Destruction of a composite should cause the destruction of its children(think about the order in which these should occrur!), atleast in the cases where Leaf objects cannot be shared.
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 28 / 62
20
18
S1The Proxy Design Pattern
. . . delegating responsibilities
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 29 / 62
20
18
S1Design Pattern: ProxyPurpose/Intent: (a.k.a. Surrogate) Provide a surrogate or placeholder foranother object to control access to itMotivation: Use a stand-in object in place of one that is expensive tocreate, until the expensive one is really needed
Applicability: Whenever there is a need for a more sophisticated reference
to an object than just a simple pointer (types next)
Benefits: Can enable optimizations such as creation only when needed
and copy only when altered
Limitations: May have issues with how to refer to the subject of the proxy
before it’s instantiated
See Also: Adapter, Decorator
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 30 / 62
20
18
S1More on ApplicabilityThere are a few different varieties of proxy with slightly differentapplicability:remote proxy provides a local representative for an object that is in adifferent address space;
virtual proxy only creates expensive objects on demand, such as keeping a
file name of an image and then only instantiating the image
when needed;
protection proxy controls access to the original object: useful when objects
should have differing access rights;
smart reference replaces a pointer and has additional functionality such as
reference counting, loading expensive objects into memory
when first referenced, etc.
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 31 / 62
20
18
S1ExampleSuppose you have a WYSIWYG document preparation system (not LATEXthen) that can include images in the documents. The images could behuge so it’s not a great idea to have to load them all in at once intomemory before they’re displayed: perhaps in a multi-page document they’d
not be observed even once through an editing session.
The Proxy pattern helps here because it makes a surrogate or placeholder
in case the image needs to be displayed.
aTextDocument
image anImageProxy
filename anImagedata
in memory on disc
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 32 / 62
20
18
S1WYSIWYG Example StructureDocumentEditor Draw()GetExtent()Store()Load()Graphic
imageImp
extent
Draw()
GetExtent()
Store()
Load()
Image
imageImp
extent
Draw()
GetExtent()
Store()
Load()
ImageProxy
image
if (image == nullptr) {
image = LoadImage(fileName);
}
image->Draw();
if (image == nullptr) {
return extent;
}
return image->GetExtent();
The document editor accesses images through Graphic interface; ImageProxy
maintains a filename as the reference to the image, which is passed to the
ImageProxy’s constructor.
ImageProxy stores the extent (bounding box) and a reference to the real image,
which will only be non-null if the image needs to be displayed (knowing the extent
without displaying it helps with the page formatting).
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 33 / 62
20
18
S1Structure Request()… Subject
Request()
…
RealSubject
Request()
…
Proxy …
realSubject->Request();
…
realSubject
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 34 / 62
20
18
S1ParticipantsProxy maintains a reference to the real subject, through whichaccess is granted; may refer to a Subject if the interfaces arethe same, and may handle creation and destruction. Otherresponsibilities of Proxy are specific to the different varieties:
remote proxies encode requests and their arguments and
pass them to Subject;
virtual proxies may cache information about the Subject
to delay accessing the real thing;
protection proxies handle access appropriately for
different clients
Subject defines the common interface for both the RealSubject and
the Proxy
RealSubject defines the real / concrete object that the proxy represents.
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 35 / 62
20
18
S1A design pattern updateWe have now looked at six of the seven structural design patterns we willconsider in this course and twelve of the twenty four design patterns wewill look at in varying detail (including RAII).
We will consider the Flyweight, the last of the structural design patterns
together with the Observer Behavioural design pattern when we discuss
the STL smart pointer in Week 11.
Before then, however, you will be introduced to a number of Behavioural
design pattern starting next week with the Iterator and the Template
Method.
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 36 / 62
20
18
S1
Topic 15: Associative Containers and STL
Algorithms
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 37 / 62
20
18
S1The Associative Containers
set, map, multimap, bitset and multiset
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 38 / 62
20
18
S1Associative Containers
set, map, multimap, bitset and multiset.
We will look at the pair class first, then map and set. The others you can
investigate yourself.
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 39 / 62
20
18
1 pair
2 pair
3 pair
make_pair(v1,v2) creates a pair from the values v1, v2, with the types
inferred from those of the arguments.
return from map::find() the iterator returned from map::find() refers
to a (key,value) pair
return from map::insert() this returns a pair whose first element is an
iterator referring to the position of the thing just inserted,
and the second element is a bool marked true if the insertion
really happened and false if there was already an element
present.
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 40 / 62
20
18
S1Associative ContainersThese containers have a restricted set of operations defined on them:constructors The first three constructors as for vector;relational operators <, <=, >, >=;end operators begin, end, rbegin, rend;
typedefs size_type, iterator, const_iterator,
reverse_iterator, const_reverse_iterator,
difference_type, value_type, reference,
const_reference;
swap and simple = assignment swap is a very quick way to swap the
contents of two collections;
clear and erase removing everything or everything-in-a-range (defined
by iterators);
size to tell how many items there are in the container.
© Drinkwater, Charleston, Scholz (USyd.SIT) INFO3220: Object Oriented Design 2018 S1 41 / 62
20
18
S1mapA map is probably what you’re most likely to imagine is an associativecontainer. It’s also known as a dictionary (Python) or a hashmap (Java) orassociative array (Perl).
A map is similar to a mathematical map, which associates with each
unique key, some kind of value. Hence we talk about (key, value) pairs.
Remember, keys are unique in a map.
Maps are declared and manipulated quite simply (don’t forget to
#include