Understanding and Implementing Abstract Factory Pattern in C++
Introduction
This article aims at understanding and implementing Abstract Factory Pattern in C++.Background
Abstract factory pattern in useful when the client needs to create objects which are somehow related. If we need to create the family of related or dependent objects, then we can use Abstract Factory Pattern. There are times when the client code does not know the exact type of object (out of many) it need to create and this pattern solves the problem by providing the client with a uniform interface to create multiple type of objects that are related by common theme.This pattern is particularly useful when the client doesn't know exactly what type to create. As an example, let's say a Showroom exclusively selling cellphones gets a query for the smart phones made by Samsung. Here we don't know the exact type of object to be created (assuming all the information for a phone is wrapped in the form of a concrete object). But we do know that we are looking for smart phones that are manufactured by Samsung. This information can actually be utilized if our design has Abstract factory implementation.
So with this idea of Abstract Factory pattern, we will now try to create a design that will facilitate the creation of related objects. We will go ahead and write a rudimentary application for the scenario we just talked about.
Using the Code
Let us start with the GOFs representation of Abstract Factory Pattern:Let's see what each class does here:
AbstractFactory
: declares an interface for operations that create abstract productsConcreteFactory
: implements the operations to create concrete product objectsAbstractProduct
: declares an interface for a type of product objectProduct
: defines a product object to be created by the corresponding concrete factory implements theAbstractProduct
interfaceClient
: uses interfaces declared byAbstractFactory
andAbstractProduct
classes
- Type of phone
- Phone manufacturer
- Nokia
- Samsung
- HTC
- Smart Phones
- Dumb Phones
Creating the Abstract Products
In our case, we need twoabstract
products ISmart
and IDumb.
//ISmart interface
class ISmart
{
public:
virtual std::string Name() = 0;
};
//IDumb interface
class IDumb
{
public:
virtual std::string Name() = 0;
};
Creating the Concrete Products
Now let us go ahead and create some concrete products forIDumb
:class Asha : public IDumb
{
public:
std::string Name()
{
return "Asha";
}
};
class Primo : public IDumb
{
public:
std::string Name()
{
return "Guru";
}
};
class Genie : public IDumb
{
public:
std::string Name()
{
return "Genie";
}
};
Let's do the same for ISmart
:class GalaxyS2 : public ISmart
{
public:
std::string Name()
{
return "GalaxyS2";
}
};
class Titan : public ISmart
{
public:
std::string Name()
{
return "Titan";
}
};
class Lumia : public ISmart
{
public:
std::string Name()
{
return "Lumia";
}
};
So we have all the concrete classes ready for all the dumb phones and smart phones irrespective of their manufacturers.Creating the Abstract Factory
Now the way we associate these Concrete products with their manufacturers is using the Concrete factories. But before having the concrete factories, we need to have an Abstract Factory.//Header File
class APhoneFactory
{
public:
enum PHONE_FACTORIES
{
SAMSUNG,
HTC,
NOKIA
};
virtual ISmart* GetSmart() = 0;
virtual IDumb* GetDumb() = 0;
static APhoneFactory* CreateFactory(PHONE_FACTORIES factory);
};
//CPP File
APhoneFactory* APhoneFactory::CreateFactory(PHONE_FACTORIES factory)
{
if(factory == PHONE_FACTORIES::SAMSUNG)
{
return new SamsungFactory();
}
else if(factory == PHONE_FACTORIES::HTC)
{
return new HTCFactory();
}
else if(factory == PHONE_FACTORIES::NOKIA)
{
return new NokiaFactory();
}
}
Creating the Concrete Factories
Now we can create our Concrete Factories for each manufacturer:class SamsungFactory : public APhoneFactory
{
public:
ISmart* GetSmart()
{
return new GalaxyS2();
}
IDumb* GetDumb()
{
return new Primo();
}
};
class HTCFactory : public APhoneFactory
{
public:
ISmart* GetSmart()
{
return new Titan();
}
IDumb* GetDumb()
{
return new Genie();
}
};
class NokiaFactory : public APhoneFactory
{
public:
ISmart* GetSmart()
{
return new Lumia();
}
IDumb* GetDumb()
{
return new Asha();
}
};
Creating the Client
Now we have all the Abstract product classes ready, all the Concrete Product classes ready. Our Abstract Factory is ready and all the Concrete Factories are ready. Now we can write client that will use this hierarchy of related products to create the products.int main(int argc, char* argv[])
{
APhoneFactory *factory = APhoneFactory::CreateFactory
(APhoneFactory::PHONE_FACTORIES::SAMSUNG);
cout << "Dumb phone from Samsung: " << factory->GetDumb()->Name() << "\n";
delete factory->GetDumb(); //USe of smart pointer will get rid of these delete
cout << "Smart phone from Samsung: " << factory->GetSmart()->Name() << "\n";
delete factory->GetSmart(); //USe of smart pointer will get rid of these delete
delete factory;
getchar();
factory = APhoneFactory::CreateFactory(APhoneFactory::PHONE_FACTORIES::HTC);
cout << "Dumb phone from HTC: " << factory->GetDumb()->Name() << "\n";
delete factory->GetDumb(); //USe of smart pointer will get rid of these delete
cout << "Smart phone from HTC: " << factory->GetSmart()->Name() << "\n";
delete factory->GetSmart(); //USe of smart pointer will get rid of these delete
delete factory;
getchar();
factory = APhoneFactory::CreateFactory(APhoneFactory::PHONE_FACTORIES::NOKIA);
cout << "Dumb phone from Nokia: " << factory->GetDumb()->Name() << "\n";
delete factory->GetDumb(); //USe of smart pointer will get rid of these delete
cout << "Smart phone from Nokia: " << factory->GetSmart()->Name() << "\n";
delete factory->GetSmart(); //USe of smart pointer will get rid of these delete
getchar();
return 0;
}
Now we can say we have a basic skeleton for the Abstract factory
pattern ready. The concrete products here are not telling anything but
names of products but they can contain more information too. Before we
end the show, we can have a class diagram for the classes we created so
that we can use this to map it with the GOFs diagram. Note: Please refer to the source code for implementation. Stepping through the code will really help in understanding this concept better.
Points of Interest
Abstract factory pattern in very useful in GUI based applications where we need to create related GUI components. My example here is solely for the purpose of understanding and there is no way the "Cell-phone-information-system" can be designed this way (otherwise we will end up adding new classes every week). Please do let me know if I missed something. There is an exact same implementation for the Factory pattern in C# available too.courtesy: http://www.codeproject.com/Articles/331304/Understanding-and-Implementing-Abstract-Factory-Pa
No comments:
Post a Comment