STRUCTURAL PATTERNS (OOAD)

 Structural Patterns:

        a) Convert the interface of a class into another interface clients expect.
        b) Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
        c) A class adapter uses multiple inheritance to adapt one interface to another.

        d) An object adapter relies on object composition.               


Example:
class Adaptee
{
public:
{
cout << "Adaptee::specificRequest" << endl;
}
};

class Target
{
public: 
virtual void request()
{
cout << "Target::request" << endl;
}
};

class Adapter : public Target
{
Adaptee obj_Adaptee;
public:
void request()
{
obj_Adaptee.specificRequest();
}
};

{
Target* tarObject = new Adapter();
tarObject->request();
}


2) Bridge:
        Decouple an abstraction from its implementation so that the two can vary independently.

Example:
{
public:
virtual void Operation() = 0;
};

class concreteImplementer1 : public Implementer
{
public:
void Operation()
{
cout << "concreteImplementer1::Operation" << endl;
}
};

class concreteImplementer2 : public Implementer
{
public:
void Operation()
{
cout << "concreteImplementer2::Operation" << endl;
}
};

class abstraction
{
public:
static Implementer* impl;

virtual void Operation() = 0;
};

Implementer* abstraction::impl = nullptr;

class refinedAbstraction : public abstraction
{
public:
void Operation()
{
impl->Operation();
}
};

void AbstractionOperation()
{
abstraction* ab = new refinedAbstraction();
ab->impl = new concreteImplementer1();
ab->impl->Operation();

cout << endl;

ab->impl = new concreteImplementer2();
ab->impl->Operation();
}

3) Composite:
        a) Compose objects into tree structures to represent part-whole hierarchies.
        b) Composite lets clients treat individual objects and compositions of objects uniformly.

Example:
class Component
{
protected:
string name;
public:
Component() {}
Component(string sName)
{
name = sName;
}

virtual void Add(Component* cp_node) = 0;
virtual void Remove(Component* cp_node) = 0;
virtual void Display() = 0;
};

class Leaf : public Component
{
public:
Leaf(string sName) : Component(sName)
{ }

void Add(Component* cp_node)
{
cout << "Cannot add to Leaf" << endl;
}

void Remove(Component* cp_node)
{
cout << "Cannot remove from Leaf" << endl;
}

void Display()
{
cout << "Leaf : " << name.c_str() << endl;
}
};

class Composite : public Component
{
list<Component* > list_leaf;
list<Component* >::iterator it;
public:
Composite(string sName) : Component(sName)
{ }

void Add(Component* cp_node)
{
list_leaf.push_back(cp_node);
}

void Remove(Component* cp_node)
{
list_leaf.remove(cp_node);
}

void Display()
{
for (it = list_leaf.begin(); it != list_leaf.end(); it++)
{
(*it)->Display();
}
}
 };

void CompositeLeaf()
{
Composite* root = new Composite("root");

root->Add(new Leaf("A"));
root->Add(new Leaf("B"));
root->Display();

cout << endl;

Composite* comp = new Composite("comp");
Leaf* If = new Leaf("If");
comp->Add(new Leaf("X"));
comp->Add(new Leaf("Y"));
comp->Add(If);
root->Add(comp);
root->Display();

cout << endl;

comp->Remove(If);
root->Display();
cout << endl;

root->Remove(comp);
root->Display();
}
        b) Decorators provide a flexible alternative to subclassing for extending functionality.


Example:
{
protected:
int numCopies;
public:
LibraryItem()
{
numCopies = 0;
}

int getNumCopies()
{
return numCopies;
}

void setNumCopies(int nCopy)
{
numCopies = nCopy;
}

virtual void Display() = 0;
};

class Book : public LibraryItem
{
string Author;
string Title;
public:
Book(string authorB, string titleB, int numCopies) : Author(authorB), Title(titleB)
{
setNumCopies(numCopies);
}

void Display()
{
cout << "Book - LibraryItem" << endl;
cout << "Book - Author         : " << Author << endl;
cout << "Book - Title          : " << Title << endl;
cout << "Book - NumberOfCopies :" << numCopies << endl;
}
};

class Video : public LibraryItem
{
string director;
string title;
public:
Video(string directorV, string titleV, int numCopies) : director(directorV), title(titleV)
{
setNumCopies(numCopies);
}

void Display()
{
cout << "Video - LibraryItem" << endl;
cout << "Video - Author         : " << director << endl;
cout << "Video - Title          : " << title << endl;
cout << "Video - NumberOfCopies :"  << numCopies << endl;
}
};

class Decorator : public LibraryItem
{
protected:
LibraryItem* libItem;
public:
Decorator(LibraryItem* lItem) : libItem(lItem) {}

void Display()
{
libItem->Display();
}
};

class Borrowable : public Decorator
{
list<string> list_Customers;
list<string>::iterator it;
public:
Borrowable(LibraryItem* lItem) : Decorator(lItem) {}

void AddCustomers(string name)
{
list_Customers.push_back(name);
int count = libItem->getNumCopies();
libItem->setNumCopies(--count);
}

void RemoveCustomers(string name)
{
list_Customers.remove(name);
int count = libItem->getNumCopies();
libItem->setNumCopies(++count);
}

void Display()
{
Decorator::Display();

for (it = list_Customers.begin(); it != list_Customers.end(); it++)
{
cout << (*it).c_str() << endl;
}
}
};

void LibraryItemFunction()
{
//Book
Book* ptr_Book = new Book("abc", "def", 5);
ptr_Book->Display();

Borrowable* ptr_BorrowBook = new Borrowable(ptr_Book);

ptr_BorrowBook->AddCustomers("AAAA");
ptr_BorrowBook->Display();

ptr_BorrowBook->AddCustomers("BBBB");
ptr_BorrowBook->Display();

ptr_BorrowBook->RemoveCustomers("AAAA");
ptr_BorrowBook->Display();

ptr_BorrowBook->RemoveCustomers("BBBB");
ptr_BorrowBook->Display();

//Video
Video* ptr_Video = new Video("ghi", "jkl", 10);
ptr_Video->Display();

Borrowable* ptr_BorrowVideo = new Borrowable(ptr_Video);

ptr_BorrowVideo->AddCustomers("CCCC");
ptr_BorrowVideo->Display();

ptr_BorrowVideo->AddCustomers("DDDD");
ptr_BorrowVideo->Display();

ptr_BorrowVideo->RemoveCustomers("CCCC");
ptr_BorrowVideo->Display();

ptr_BorrowVideo->RemoveCustomers("DDDD");
ptr_BorrowVideo->Display();
}


5) Facade:
        a) Provide an unified interface to a set of interfaces in a subsystem.
        b) Facade defines a higher-level interface that makes the subsystem easier to use.

Example:
class subSystem_1
{
public:
void func_sub1()
{
cout << "subSystem_1::func_sub1" << endl;
}
};

class subSystem_2
{
public:
void func_sub2()
{
cout << "subSystem_2::func_sub2" << endl;
}
};

class subSystem_3
{
public:
void func_sub3()
{
cout << "subSystem_3::func_sub3" << endl;
}
};

class subSystem_4
{
public:
void func_sub4()
{
cout << "subSystem_4::func_sub4" << endl;
}
};

class Facade
{
subSystem_1* ptr_sub1;
subSystem_2* ptr_sub2;
subSystem_3* ptr_sub3;
subSystem_4* ptr_sub4;
public:
Facade()
{
ptr_sub1 = new subSystem_1();
ptr_sub2 = new subSystem_2();
ptr_sub3 = new subSystem_3();
ptr_sub4 = new subSystem_4();
}

void Method_A()
{
cout << "Facade::Method_A()" << endl;

ptr_sub1->func_sub1();
ptr_sub2->func_sub2();
}

void Method_B()
{
cout << "Facade::Method_b()" << endl;

ptr_sub3->func_sub3();
ptr_sub4->func_sub4();
}
};

void FacadeFunction()
{
Facade objFacade;
objFacade.Method_A();
cout << endl;
objFacade.Method_B();
}

        Use sharing to support large numbers of fine-grained objects efficiently.


            The following object diagram shows how flyweights are shared:


Example:
class FlyWeight
{
public:
virtual void operation(int extrinsicState) = 0;
};

class concreteFlyWeight : public FlyWeight
{
public:
void operation(int extrinsicState)
{
cout << "concreteFlyWeight::operation" << endl;
}
};

class unsharedConcreteFlyWeight : public FlyWeight
{
public:
void operation(int extrinsicState)
{
cout << "unsharedConcreteFlyWeight::operation" << endl;
}
};

class FlyWeightFactory
{
map<string, FlyWeight*> map_FlyWeight;
public:
FlyWeightFactory()
{
pair<string, FlyWeight*> pair_FlyWeight1("A", new concreteFlyWeight);
pair<string, FlyWeight*> pair_FlyWeight2("B", new concreteFlyWeight);
pair<string, FlyWeight*> pair_FlyWeight3("C", new concreteFlyWeight);
pair<string, FlyWeight*> pair_FlyWeight4("D", new unsharedConcreteFlyWeight);

map_FlyWeight.insert(pair_FlyWeight1);
map_FlyWeight.insert(pair_FlyWeight2);
map_FlyWeight.insert(pair_FlyWeight3);
map_FlyWeight.insert(pair_FlyWeight4);
}

FlyWeight* getFlyWeightFactory(string key)
{
map<string, FlyWeight*>::iterator it = map_FlyWeight.find(key);

if (it != map_FlyWeight.end())
return map_FlyWeight[key];
else
{
Create(key);
return map_FlyWeight[key];
}
}

void Create(string key)
{
pair<string, FlyWeight*> pair_FlyWeight1(key, new concreteFlyWeight);
map_FlyWeight.insert(pair_FlyWeight1);
}

void Display()
{
map<string, FlyWeight*>::iterator it;

for (it = map_FlyWeight.begin(); it != map_FlyWeight.end(); it++)
{
cout << it->first << " " << it->second << endl;
}
}
};

void FlyWeightFunction()
{
int extrinsicState = 22;

FlyWeightFactory fwf;

FlyWeight* fw1 = fwf.getFlyWeightFactory("A");
fw1->operation(extrinsicState--);

fw1 = fwf.getFlyWeightFactory("B");
fw1->operation(extrinsicState--);

fw1 = fwf.getFlyWeightFactory("C");
fw1->operation(extrinsicState--);

fw1 = fwf.getFlyWeightFactory("D");
fw1->operation(extrinsicState--);

fw1 = fwf.getFlyWeightFactory("E");
fw1->operation(extrinsicState--);

fw1 = fwf.getFlyWeightFactory("F");
fw1->operation(extrinsicState--);

fw1 = fwf.getFlyWeightFactory("G");
fw1->operation(extrinsicState--);

fwf.Display();
}

7) Proxy:
        Provide a surrogate or placeholder for another object to control access to it.


Here's a possible object diagram of a proxy structure at run-time:


Example:
class abs_proxy { public: virtual void func1() = 0; virtual void func2() = 0; }; class abs_implementation : public abs_proxy { public: void func1() { cout << "abs_implementation::func1" << endl; } void func2() { cout << "abs_implementation::func2" << endl; } }; class abs_surrogate : public abs_proxy { abs_proxy* obj_proxy; public: abs_surrogate() { obj_proxy = new abs_implementation(); } void func1() { obj_proxy->func1(); } void func2() { obj_proxy->func2(); } }; void absSurrogate_Function() { abs_surrogate abs_sur; abs_sur.func1(); abs_sur.func2(); }

Popular posts from this blog

OBJECT ORIENTED ANALYSIS AND DESIGN (OOAD)

OBJECT ORIENTED PROGRAMMING

STARTING A BUSINESS