STRUCTURAL PATTERNS (OOAD)
Structural Patterns:
1) Adapter:
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.
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:
void specificRequest()
{
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();
}
};
void AdapterFunction()
{
Target* tarObject = new Adapter();
tarObject->request();
}
2) Bridge:
Decouple an abstraction from its implementation so that the two can vary independently.
class Implementer
{
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.
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();
}
4) Decorator:
b) Decorators provide a flexible alternative to subclassing for extending functionality.
class LibraryItem
{
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.
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();
}
6) Flyweight:
Use sharing to support large numbers of fine-grained objects efficiently.
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.
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();
}