object- oriented programming part ii• allows us to substitute properly implemented objects of...

64
C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002 Chapter 6 Object- Oriented Programming Part II

Upload: others

Post on 30-Sep-2020

5 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

Chapter 6

Object-Oriented

ProgrammingPart II

Page 2: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Preview

• issues surrounding the object creational process• the Abstract Factory design pattern• private and protected inheritance• multiple inheritance• comparison of delegation and inheritance• programming to an interface• several new design patterns:

- Prototype- Bridge- Adapter- State

Page 3: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Managing the Creational Process, Part II: Abstract Factory Design Pattern

• the Instantiating Operation Idiom specified how to design classes so that you can take control over the creation of their objects

• the Singleton design pattern was designed so that at most one instance of a class may be created

• the Abstract Factory design pattern is used to manage the general creational process in the context of classes and inheritance

Page 4: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Managing the Creational Process, Part II (cont.)

When a class constructor is used to create an object, it creates several dependencies: • it makes your code dependent on the objects of this particular class, • it makes it dependent on the name of the specific class used to

create it (the class name is said to be hard-coded).

Is there anything wrong with hard coding class names? It makes it difficult to modify your program, should you want to

replace some class in the program with a different class, say because the new class has a better implementation, but has the same behavior.

Page 5: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Managing the Creational Process, Part II (cont.)

Consider a polynomial or a rational function represented by a string. In order to operate on the function, for example to display it:• you need to read in the string• after the string is read, you have to parse it to decide on the type of

function it represents• use it to create an object of type Polynomial or an object of

type Rational• then use its interface to perform the display operation. If you are hard coding the class used to create new objects in your

program, then whenever new function types are added, each part of the code that creates objects representing these functions has to be modified.

Page 6: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Managing the Creational Process, Part II (cont.)

Solution: • encapsulate the creation of objects in another class• use the interface of this class to get new objects whenever they are

required. Any future changes to the creational process will be isolated to the class that produces objects.

Terminology:• the object being created is a product• the object that creates other objects is a factory; responsible for

producing a specific product using a factory method.

Page 7: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Managing the Creational Process, Part II (cont.)

In our case of mathematical functions we have two products: • a polynomial function • a rational function

Your code would use two classes: • an abstract product class, i.e. the base class for all products, • the factory class; the factory method has a string parameter to decide

which product it should produce.

Page 8: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Managing the Creational Process, Part II (cont.)

Actions:• create a factory object• use its factory method to create a specific product • use the abstract product interface to invoke the required operation

for a product; for example, to display the rational function.

The product dependency is now encapsulated in the factory class, which means that the remainder of your code is not dependent on a specific product.

Page 9: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Managing the Creational Process, Part II (cont.)

To construct an object, you need to know the type of this object:• the constructor cannot be virtual• it cannot be abstract, which would allow the derived class to decide

what type of object is created.

A factory method is virtual:AbstractProduct* Factory::factoryMethod(...);

returns a product derived from the class AbstractProduct.

Also known as a virtual constructor: various classes derived from Factory, such as AnotherFactory can decide on the specific type of a product to create.

Page 10: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Managing the Creational Process, Part II (cont.)

The factory method is often useful in combination with the Template Method pattern.If the template method needs to create an object, then it can use a factory method rather than hard coding class names.

Consider an abstract class Factory, which has a factory method to create products. These products are derived from an abstract class Product. • Concrete factories (classes derived from Factory) create concrete

products. • A template method templateOP() uses the factory method to return

objects of classes derived from the class Product

Page 11: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Managing the Creational Process, Part II (cont.)

The client who wants to invoke the template method:• creates a concrete factory• calls the template method; this method will use a factory method to

create a product, and then use this product.

Page 12: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Abstract Factory

The Abstract Factory:an abstract class with a method to return specific factories. Also has abstract factory methods to return instances of concrete derived classes of the abstract product. The user of this never creates objects directly; instead, gets a factory and asks this factory to create a concrete product.

Page 13: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Abstract Factory (Example)

A system where various kinds of objects are created:• from interactive file input on a local machine• from a remote machine on the network.

The user should be able to code to the same interface:• An abstract product class with two abstract functions to open a file

for reading and writing• Two concrete product classes derived from this abstract class that

implement a local and a remote file access• a concrete factory has createAbstractProduct(string fname) to

examine fname and depending on whether it represents a local filename or a remote filename, to return the appropriate concrete product.

Page 14: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Abstract Factory (Example)

Various simple file operations, such as computing the number of lines in a file can be implemented:

• without caching• with caching

We need to create two different products (instances that either do or do not cache). The responsibility of creating products will be assigned to an abstract factory method; the derived class will implement this abstract method as a function returning an instance of this class.

The function lines() is a template method that uses the factory method to create the product (which is a cached or a non-cached application), and then invokes the operation lines() from this product.

Page 15: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Abstract Factory (Example)

Page 16: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

Abstract Factoryclass AbstractFileOps { //abstract productpublic:

virtual long lines() const = 0; protected:

virtual ~AbstractFileOps();};

Page 17: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

Abstract Factoryclass FileOps : public AbstractFileOps { // implements

public: // concrete

virtual long lines() const; // product

FileOps(const string&);~FileOps();

private:mutable ifstream fileVar_;

};

class CachedFileOps : public AbstractFileOps {public:virtual long lines() const;virtual void clearCache();CachedFileOps(const string&);~CachedFileOps();

private:mutable long lines_;mutable bool linesCached_;mutable ifstream fileVar_;

};

Page 18: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

Abstract Factoryclass AbstractApplication { // abstract factorypublic:virtual AbstractFileOps* factoryMethod() const = 0;long lines() const; // template method

virtual ~AbstractApplication();};

long AbstractApplication::lines() const { AbstractFileOps* afo = factoryMethod();return afo->lines();

}

AbstractApplication::~AbstractApplication() {}

Page 19: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

Abstract Factoryclass RegularApplication : public AbstractApplication { public: // concrete factory implements

RegularApplication(const string&);~RegularApplication();virtual FileOps* factoryMethod() const;

private:string filename_;

};

class CachedApplication : public AbstractApplication { public:

CachedApplication(const string&);~CachedApplication();virtual CachedFileOps* factoryMethod() const;void clearCache();

private:string filename_;

};

Page 20: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

Abstract FactoryFileOps* RegularApplication::factoryMethod() const {

return new FileOps(filename_);}

RegularApplication::RegularApplication(const string& filename) : filename_(filename) {}

CachedFileOps* CachedApplication::factoryMethod() const {return new CachedFileOps(filename_);

// same kind of constructor for CachedApplication

void CachedApplication::clearCache() {CachedFileOps* cs = factoryMethod();cs->clearCache();

}

Page 21: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

Abstract Factoryint main(int argc, char* argv[]) {if(argc != 3) {cerr << "usage " << argv[0] << " file1 file2" << endl;return 1;

}

AbstractApplication* aa= new CachedApplication(argv[1]);AbstractApplication* bb= new RegularApplication(argv[2]);

cout<<"lines in "<<argv[1] << " " << aa->lines() << endl;cout << "clear cache" << endl;aa->clearCache();

cout<<"lines in "<<argv[1] << " " << aa->lines() << endl;cout<<"lines in "<<argv[2] << " " << bb->lines() << endl;}

Page 22: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Abstract Factory (Example)

Page 23: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

Abstract Factoryclass FunctionFactory { // abstractpublic:virtual Function* createFunction(const string&) const=0;static FunctionFactory* getFactory(const string&);};

FunctionFactory* FunctionFactory::getFactory(const string& s) {

string::size_type pos = s.find_first_of('/');// if s represents a polynomial

if(pos == string::npos)return new PolynomialFactory();

return new RationalFactory();}

Page 24: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

Abstract Factoryclass PolynomialFactory : public FunctionFactory {public:virtual Polynomial* createFunction(const string&) const;};

class RationalFactory : public FunctionFactory {public:virtual Rational* createFunction(const string&) const;virtual ~RationalFactory();

};

Rational* RationalFactory::createFunction(const string& s) const {

return new Rational(s);}

Page 25: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Abstract Factory (Example)

An application in which you use two kinds of functions: polynomials and rational functions (quotients of two polynomials).The client of the program uses an abstract factory, FunctionFactory and an abstract product, Function.There are two concrete factories, RationalFactory and PolynomialFactory to create the concrete products Rationaland Polynomial:

string s;cin >> s;FunctionFactory* factory = FunctionFactory::getFactory(s);Function* foo = factory->createFunction(s);foo->display();

Page 26: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Private Inheritance

Public inheritance:• all public features of the base class are inherited • allows us to substitute properly implemented objects of derived

classes for objects of the base class.

Private inheritance:• don’t inherit the entire interface• don’t inherit even a part of the entire interface• inherit just the implementation of the various operations. For

example, you may need to operate on data with more stringent requirements, and so may need to restrict the original interface

Page 27: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Private Inheritance (cont.)

class Dequeue { public:Dequeue(int size = 10);virtual ~Dequeue();void insertL(int);void insertR(int);int removeL();int removeR();

protected:int size_;int* elem_; int left_;int right_;

};

Page 28: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Private Inheritance (cont.)class Queue: private Dequeue { // note: private

public:using Dequeue::insertL; // restore insertL();

using Dequeue::removeR; // restore removeR();Queue(int size = 10);virtual ~Queue();

};

equivalent to:class Queue { //PSEUDO-CODEpublic:void insertL(int);int removeR();Queue(int size = 10);virtual ~Queue();

private:…

Page 29: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Private Inheritance (cont.)class Stack : private Dequeue {// doesn't inherit the interface

public:Stack(int size = 10);~Stack();void push(int);int pop();bool full() const;

};void Stack::push(int i) {insertL(i);

}bool Stack::full() const {return left_ == right_;

}

Page 30: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Private Inheritance (cont.)

Since the interface is not inherited, private inheritance does not support isA relationships:

• a Queue is not a Stack• Queue objects cannot be used where Stack objects are expected.

Private inheritance represents a is-implemented-in-terms-of relationship:

• Stack is-implemented-in-terms-of Dequeue.

In other words, private inheritance allows the derived class to reuse the code of the base class.

Page 31: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Protected Inheritance Protected inheritance: • all public features of the base class become protected features of the

derived class (protected features of the base class continue to be protected in the derived class)

• useful if you do not want to finalize the derivations, that is you want to make it possible to have additional derived classes:

class Stack : protected Dequeue {public:Stack(int size = 10);~Stack();void push(int);int pop();bool full() const;

};

Page 32: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Revisiting Inheritance A default implementation of a virtual function may turn out to be dangerous, because the designer of the derived class may forget to add her or his own implementation:

class Shape {public:virtual void draw() const;...

};void Shape::draw() {... // default implementation; draws a logo shape

}

class Rectangle : public Shape {

public:... // no draw() here

};

Page 33: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Revisiting Inheritance

Shape* s = new Rectangle;s->draw(); // draws the logo, not the rectangle

You can force the inheriting clients to provide their own implementations, and have a default implementation in the base class:class Shape { // abstractpublic:virtual void draw() const = 0;...

};void Shape::draw() {// default implementation; draws a logo shape

...}

Page 34: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Revisiting Inheritance

class Rectangle : public Shape { // still abstractpublic:... // no implementation of draw()

};

Shape* s = new Rectangle;s->draw(); // Rectangle is abstract

The base class default implementation of draw() can be used to implement the derived implementation:

void Rectangle::draw() {Shape::draw(); // default implementation... // specific for Rectangle

}

Page 35: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

To provide a default implementation that must be redefined in a derived class, use pure virtual operations and provide their implementation.

Default Implementation

Page 36: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Inheritance versus Delegation

• white-box reuse through inheritance. Internals of the parent classes are visible to the derived classes. Uses a compile-time relationship between two classes (a base class and a derived class) and you cannot make modifications at run-time.

• black-box reuse through delegation. Internal details of the objects are not visible. Uses a runtime-time relationship between two objects.

white-box black-box

Page 37: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Inheritance versus Delegation (cont.)

-The handle represents an abstraction, and is visible to the client-The invisible body provides the implementation.-Object composition combined with inheritance is often a better alternative than just inheritance:• the client programs according to an interface provided by a class (the

handle) whose object delegates requests to the object providing the implementation (the body).

• the client's code only has to be relinked with the modified code• decomposes an abstraction into smaller, more manageable parts• helps the programmer to define additional functionality for the

implementation without affecting the client; e.g. support for the sharing of objects by using reference counting

Page 38: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Multiple Inheritance, Part I C++ Comments about C++

class CE : public Ifc {

public derivation to implement abstract interface

class Ifc : public Ifc1, public Ifc2 {

public derivation to extend abstract interfaces of several classes

class CE : public C {

public derivation to inherit an interface

class CE : public C, public Ifc {

public derivation to implement abstract interface and derived class

class CE : private C, public Ifc {

public derivation from the interface and private derivation from the class (mixin class).

Page 39: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Programming to an Interface

One of the important goals in writing good code is reusability:minimize the dependencies between subsystems

Program to an interface, not an implementation

• access objects in terms of their abstract interfaces, that is interfaces consisting entirely of abstract operations

• do not use concrete operations because this requires binding to a specific implementation.

Page 40: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Decoupling Interfaces and Implementations

The Account class is abstract; there may be various derived classes, such as SavingsAccount, which implement Account. The handle class Bank does not need to be changed when new derived classes are used.

Page 41: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: The Bridge design pattern

Using inheritance to provide implementations of a single abstraction:• tightly binds these implementations to the abstraction• makes it difficult to update the client's code, and reuse the abstraction.

In C++, the complete class definition, including the private and protected sections, is needed in order to compile the client's code• leads to a tight coupling between the abstraction and its

implementations• makes modifications more difficult.

The Bridge Design Pattern – a structural patternseparates and decouples the abstraction and the implementation

Skip Bridge

Page 42: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: The Bridge design pattern (cont.)

There are two independent class hierarchies bridged through a delegate. Implementation details are hidden from the clients, who access only the abstraction. Both the abstraction and the implementation classes can be extended independently.

Page 43: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Reference Counting

You can use the Bridge Design Pattern to share objects and use reference counting to deallocate them when they are no longer used:• have the counters in the body• have the copying operations in the handle.

These copying operations could include dealing with things like object assignments:• incrementing the reference counter of the right hand side• decrementing the reference counter of the left hand side

Page 44: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Reference Counting (cont.)class Point { public:Point(double = 0, double = 0);virtual ~Point(); double getX() const;double getY() const;

private:double x_;double y_;

};

To add reference counters to Point objects, we need to create a new class, here called PointCounted, which is used by the clients. Therefore, this PointCounted class is the handle, while the class Pointis the body.

Page 45: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Reference Counting (cont.)class PointCounted {public:PointCounted(double = 0, double = 0); //creates a point PointCounted(const PointCounted&);PointCounted(const Point&); PointCounted& operator=(const PointCounted&);~PointCounted();double getX() const;double getY() const;

private:Point* p_;int* count_;

};

Page 46: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

PointCountedPointCounted::PointCounted(double x, double y) {

p_ = new Point(x, y);

count_ = new int(1);

}

PointCounted::PointCounted(const Point& pp) {

p_ = new Point(pp);

count_ = new int(1);

}

PointCounted::~PointCounted() {

--(*count_); // one fewer reference

if (*count == 0) // garbage

{ delete p_; delete count_; }

}

double PointCounted::getX() const {

return p_->getX(); // same for Y

}

Page 47: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

PointCountedPointCounted::PointCounted(const PointCounted& pc) {

count_ = pc.count_;

p_ = pc.p_;

++(*count_);

}

PointCounted& PointCounted::operator=(const PointCounted& pc) {

if(this == &pc) return *this;

++(*pc.count_); // RHS has one more reference

--(*count_); // LHS has one less reference

if(*count_ == 0) { // garbage

delete p_;

delete count_;

}

count_ = pc.count_;

p_ = pc.p_;

return *this;

}

Page 48: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Reference Counting (cont.)PointCounted p1(1, 3);if(...) { PointCounted p2(p1); // share the same pointcout << p1.getX() << " " << p2.getY() << endl;

} // now there is only one copyPointCounted p2(14, 4); p1 = p2; // one copy is collected

Page 49: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

To avoid the need for unnecessary recompilation of the client's code, separate the interface and the implementation, and include only those header files that are absolutely necessary.

Avoiding Recompilation

Page 50: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Creating and Copying Abstract Interfaces: Prototype Design Pattern

The cloning operation has its roots in yet another creational design pattern:

the Prototype design pattern gives a flexible alternative to inheritance. The client class creates a prototype object; when this client again needs to create a new object, it asks the prototype object to clone itself. Therefore, objects that are used as prototypes must support the clone() operation, in addition to their own operations

Skip Prototype

Page 51: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Creating and Copying Abstract Interfaces: Prototype Design Pattern (cont.)

Application of the Prototype design pattern:the creation and copying of an abstract interface.

Page 52: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

Accountclass Account { // abstract prototypepublic:virtual void open() = 0;virtual void withdraw(double) = 0;virtual void deposit(double) = 0;virtual Account* clone() const = 0;virtual Account* create() const = 0;

};class SavingsAccount : public Account { // implementspublic:virtual void open();virtual void withdraw(double);virtual void deposit(double);virtual SavingsAccount* clone() const; virtual SavingsAccount* create() const;

protected:...

};

Page 53: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

AccountSavingsAccount* SavingsAccount::clone() const {return new SavingsAccount(*this);

};SavingsAccount* SavingsAccount::create() const {return new SavingsAccount();

};

The variable prot is assumed to point to the prototype account:Account* a = prot->clone();

If the value of the prot is an object of the class SavingsAccount, thenclone() returns an object of the same class (polymorphism).

How do we create the initial prototype?

Page 54: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

Accountclass BankFactory {public:BankFactory(Account*);virtual Account* makeAccount() const;

private:Account* accPrototype_;

};BankFactory::BankFactory(const Account* a) {accPrototype_ = a;

}

To configure a factory for a particular type of account:BankFactory saving(new SavingsAccount());

The client of BankFactory can use its operation makeAccount() to clone the prototype:Account* BankFactory::makeAccount() const {return accPrototype_->clone();

}

Page 55: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

AccountNow, let's look at the client code:

Account* sa = saving.makeAccount();

Account* sa1 = sa->clone();//clone existing saving accountAccount* sa2 = sa->create(); // create new saving account

Page 56: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Creating and Copying Abstract Interfaces: Prototype Design Pattern (cont.)

-delegate_:Account*

Page 57: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Modifying Existing Interfaces: Adapter Design Pattern

Consider a class, called Adaptee with a given interface, and an application that needs almost exactly this kind of an interface, but with some minor differences.

Modifying the class interface is not necessarily a feasible solution; it would really be useful to adapt the existing Adaptee to the needs at hand.

The Adapter Design Pattern can help us to accomplish precisely this. The pattern is an example of a structural pattern:

how to compose existing objects and classes to form new structures.

Skip Adapter

Page 58: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Modifying Existing Interfaces: Adapter Design Pattern (cont.)

Class adapters: use mixins to inherit and implement the interface of TargetIfc and to inherit only the implementation of Adaptee

Page 59: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Modifying Existing Interfaces: Adapter Design Pattern (cont.)

Object adapters: use object composition to delegate requests to Adaptee

Page 60: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

Adapterclass DictionaryNamespace::DictionaryIfc { // abstract

public:virtual void insert(const string&) = 0; virtual void remove(const string&) = 0;virtual bool member(const string&) const = 0;

};class OldStuffNamespace::Dictionary { // existing

public:void insert(const char* const); void remove(const char* const);bool member(const char* const) const;

private:... // not shown here

};

In order to implement DictionaryNamespace::DictionaryIfc

an adapter mixin class ClassDictionaryAdapter

Page 61: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

Adapterclass DictionaryNamespace::ClassDictionaryAdapter : public DictionaryNamespace::DictionaryIfc // implementsprivate OldStuffNamespace::Dictionary { // inherit impl.

public:virtual void insert(const string&); virtual void remove(const string&);virtual bool member(const string&) const;

};

void DictionaryNamespace::DictionaryAdapter insert(const string& s) {OldStuffNamespace::Dictionary::insert(s.c_str());

}

Page 62: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Self-modifying Interfaces: State Design Pattern

The State pattern is useful if an object may be in a large number of states, and the behavior of this object changes at run-time whenever its state changes.

Rather than coding the behavior using a large switch statement, this behavior is implemented by the subclasses of the state.

Skip State

Page 63: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Self-modifying Interfaces: State Design Pattern (cont.)

The client of the State Design Pattern communicates with a class called Context. This design pattern also includes an abstract class called the State; concrete states implement this class’s behavior.

Page 64: Object- Oriented Programming Part II• allows us to substitute properly implemented objects of derived classes for objects of the base class. Private inheritance: • don’t inherit

C++ Programming with Design Patterns Revealed Tomasz Müldner Copyright: Addison-Wesley Publishing Company, 2002

6: Self-modifying Interfaces: State Design Pattern (cont.)

An example of an application of the State design pattern:TCP connections where a TCP object may be in several states, such as:• Established • Closed• Listening. When a TCP connection object receives a request, its response depends

on its state.For example, the action taken for an Open request depends on whether

the current state is Established or Closed.