P.YOGESHWARAN (21USC031)
M.GUNA (21USC008)
III B.Sc Computer Science
SRMVCAS
DESIGN
PATTERNS
Design patterns are typical solutions to common problems in software
design. Each pattern is like a blueprint that you can customize to solve a
particular design problem in your code.
Classification
of patterns
Design patterns differ by their complexity, level of detail and scale of
applicability to the entire system being designed. I like the analogy to road
construction: you can make an intersection safer by either installing some
traffic lights or building an entire multi-level interchange with underground
passages for pedestrians.
In addition, all patterns can be categorized by their intent, or
purpose. This book covers three main
groups of patterns:
v
Creational patterns provide object creation mechanisms that increase flexibility and reuse
of existing code.
v
Structural patterns explain how to assemble objects and classes into larger structures,
while keeping these structures flexible and efficient.
v
Behavioral patterns take care of effective communication and the assignment of
responsibilities between objects.
Creational Design Pattern
Creational
design patterns are design patterns which focus
on creating objects effectively. They bring flexibility to the
software design and help in the reusability of existing code. There are
mainly 6 types of creational design patterns: Factory
Method, Abstract Factory, Singleton, Prototype, Builder and Object
Pool pattern.
What
are Creational Design Patterns?
A design pattern refers
to a generalized, reusable solution to commonly occurring scenarios in software
design. Creational design patterns are design patterns that
focus on creating objects effectively.
This is where creational design
patterns come to the rescue. Creational design patterns provide object
creation mechanisms that reduce the level of complexity in our design.
They help in creating objects in a more generalized way that increases flexibility and
enables the reuse of existing code.
There
are mainly 6 types of creational design patterns:
1.
Factory Method,
2.
Abstract Factory,
3.
Singleton,
4.
Prototype,
5.
Builder ,
1.
Factory Method Pattern
Factory
Method creates an instance of several derived classes
belonging to a single family of objects. It helps to create objects
in a superclass but also allows the subclasses to modify the type of objects
that are created. We can hide the existence of classes from the end
user using the Factory Method pattern. Usually, a software design
starts with a Factory Method which is comparatively simpler and more
customizable.
Suppose we
go to an ice cream factory and order a chocolate ice cream. When we place an
order, the shopkeeper sends the order to the kitchen and we get it in a few
minutes when the ice cream is ready. We are not concerned with what happens
inside the kitchen and what ingredients are used to make the ice cream. The
internal call by the shopkeeper to create a vanilla, chocolate, or strawberry
ice cream is hidden from the user.
1.
Abstract Factory Pattern
Abstract
Factory pattern creates an object of several
families of classes. It lets us produce families of related objects without
specifying their concrete classes. While a Factory Method can produce only one
type of object (only icecreams), an Abstract Factory can produce a
family of different kinds of objects (multi-course and multi-cuisine
meals). One generalized factory can consist of multiple specialized
factories, each producing a different kind of object.
Let’s take
an example of a multi-cuisine restaurant that serves Chinese, Indian, and
Continental food and you opt for Chinese. There might be different specialized
chefs for the different items and for different cuisines but you don’t need to
get into the details. In fact, you would not even know which kitchen or chef is
involved in preparing your food.
1.
Singleton Pattern
Singleton is
one of the simplest design patterns. It means that only one instance
can be instantiated from a given class. It ensures that a class has
only one instance and provides a global access point to this particular
instance. Singleton pattern helps in saving memory since the
object is not created at every request. It either creates a new object or
returns an existing object which has already been created.
For
example, a single database object which is shared by all the different parts of
a program is an example of a singleton class.
1.
Prototype Pattern
Prototype pattern creates a fully
initialized instance that can be cloned. It lets us copy already existing
objects without making the code dependent on other classes. A prototype pattern
builds a product by copying the initial state of a prototype object.
We can take a board game like chess
as an example. The initial setup of a chess board is initialized once with the
king, rooks, bishops, and other pieces in their designated places. Every time a
new game starts, we call this object with the initial setup is already done,
clone it and begin the game. There’s no need to create a new setup every single
time the game is played.
1.
Builder Pattern
Builder pattern separates the complex
object construction from its representation. It hides the internal structure
from the end user and provides an easy interface to the outside world. Builder
pattern focuses on constructing a complex product incrementally. It
is designed as a composition of one or more similar objects having similar
functionality. It allows us to produce different types of an object using the
same code.
Imagine you and your friend go to
Subway and order your favorite subs. Your choice of bread, salad, and toppings
may be very different but the process of making the sub is similar. You may
choose the same bread but a different topping - the final object (sub) is
different but the process (code) to make the sub is the same.
Creational Pattern in C++
Generally, a system has information about its object’s
creation, composition, and representation. Creational patterns have handled
everything from object creation to its representation.
- The system does not need to worry about how its objects
are created, represented, etc. Such creational patterns are known as
object creational patterns. That delegates object instantiation to another
object.
- In addition to this, there are creational patterns that
can also manage the instantiation process of classes by using the concept
of inheritance. These patterns are called creational patterns, out of
these two patterns, more importance is given to object creational
patterns. They define a small set of fundamental behaviors that can
perform more complex tasks rather than defining a fixed set of behaviors.
- Creational patterns contain information about concrete
classes, that are mostly used by the system.
- They do not provide information about how different
instances of concrete classes are created and how they are combined
together.
- The only thing the system knows about its objects is the
interfaces of objects that are declared by the abstract classes.
Based on the above two categories of
creational patterns i.e. object and class, there are 5 types of
creational patterns with all of them being object creational patterns
except the Factory Method pattern, which is a class creational pattern.
1.
Abstract Factory Patterns
Example: Consider the example of a maze game in which a
member function create() of a class Maze_Game is used to build a maze.
The problem with that code is, it was written to create only two rooms with a
door between them. Hence, this makes it difficult to create a maze with
different components. To overcome this problem, a MazeFactory (MF) class is created
that creates rooms, according to the specification of doors, walls, and rooms
specified by the programmer.
#include <iostream>
using namespace std;
// Code of Maze_Factory Class is flows,
class Maze_Factory {
public:
Maze_Factory(); // Constructor
virtual Maze* createMaze() const { return new Maze; }
virtual Rooms* createsRooms(int rno) const
{
return new Rooms(rno);
}
virtual Wall* createsWall() const { return new wall; }
virtual Wall* createsWall() const;
{
return new Wall;
}
virtual Door* createsDoor(Room*
ro1, Room*, ro2) const
{
return new Door(ro1, ro2);
}
};
// Therefore the code for creating a maze using an object
of
// A Maze_Factory as a parameter is given below,
Maze* Maze_Game::create(Maze_Factory& f)
{
Maze* m = f.createMaze();
Room* ro1 = f.createRoom(1);
room* ro2 = f.createRoom(2);
Door* d = f.create Door(ro1, ro2);
m-- > addRoom(ro1);
m-- > addRoom(ro2);
// create room1
ro1-- > setSide(North,
f.createwall());
ro1-- > setSide(south,
f.createwall());
ro1-- > setSide(East, d);
ro1-- > setSide(West,
f.createwall());
// create room2
ro2-- > setSide(North,
f.createwall());
ro2-- > setSide(South,
f.createwall());
ro2-- > setSide(East,
f.createWall());
ro2-- > setSide(West, d);
return m;
}
2. Builder Patterns
Example: Consider the maze game example. The
MazeUsing-Builder class defines an interface for creating a maze.
#include <iostream>
using namespace std;
class MazeUsingBuilder {
public:
virtual void createMaze() {}
virtual void createMaze(into) {}
virtual void createDoor(int fromRoom,
int toRoom)
{
}
virtual Maze* getMaze()
{
return 0;
}
protected:
MazeUsingBuilder();
};
The above class consists of 4 methods where the
methods createMaze(), create room(), and createDoor() create a maze, rooms with
particular room number and door between numbered rooms respectively. The
getMaze()method returns the maze to the client but, by default these operations
do nothing. They are overridden by subclasses of MazeUsingBuilder class.
3.
Factory
Method Pattern
Example: Consider the maze game example. As
already mentioned, the problem with createMaze()is that the MazeUsingFactory
defines the factory methods for different components like the maze, rooms, and
walls. The factory methods allow the subclasses to choose these components.
class MazeUsingFactory
{
public:
virtual Maze*createMaze()const
{
return new Maze;
}
virtual Room*createRoom()const
{
return new Room(N);
}
virtual Wall*create()const
{
return new Wall;
}
virtual Door*createDoor(Room*ro1,Room*ro2)const
{
return new Door(ro1,ro2);
}
}
4.
Prototype Pattern
Example: A
subclass of MazUsingFactory class is created called MazeUsingPrototype. In this
class, the prototype of objects of Maze, Room, Wall, and Door classes are first
created and then initialized. This Initialization is done through a
parameterized constructor which is added to MazeUsingFactory.
class MazeUsingPrototype : public MazeUsingFactory
{
public:
MazeUsingProtype(Maze*, Wall*,
Room*, Door*);
virtual Maze* createMaze() const;
virtual Room* createRoom(int)
const;
virtual Wall* createWall() const;
virtual Door* createDoor(Room*,
Room*) const;
private:
Maze* Maze_prototype;
Room* Room_protype;
Wall* Wall_prototype;
Door* Door_prototype;
}
MazeUsingPrototype::MazeUsingProtype
(Maze* mz, Wall* wl, Room* rm, Door* dr)
{
Maze_prototype = mz;
Wall_Prototype = wl;
Room_Prototype = rm;
Door_Prototype = dr;
}
5.
Singleton Pattern
Example:
class Singleton
{
public:
static Singleton* Instance();
protected:
Singleton();
private:
static Singleton* oneInstance();
};
// implementation of Instance() is given below
Singleton* Singleton::oneInstance = 0;
Singleton* Singleton:: Instance();
{
if(oneInstance==0)
{
oneInstance = new Singleton;
}
return oneInstance;
}
Here, for the Singleton class, it can be observed
that the constructor of this class is of type protected. Hence when any client
tries to directly instantiate this class or create another instance, an error
message will be displayed during the compilation of this code. Therefore, this
ensures that a class can have no more than one instance.
Comments
Post a Comment