factory method pattern (virtual constructor)

21
Factory Method Pattern Virtual Constructor Sameer Singh Rathoud

Upload: sameer-rathoud

Post on 25-May-2015

1.219 views

Category:

Technology


0 download

DESCRIPTION

This presentation provide information to understand factory method pattern, it’s various implementation and Applicability. Major focus is on implementation of factory method pattern using reflection and without reflection.

TRANSCRIPT

Page 1: Factory method pattern (Virtual Constructor)

Factory Method PatternVirtual Constructor

Sameer Singh Rathoud

Page 2: Factory method pattern (Virtual Constructor)

About presentation

This presentation provide information to understand factory method pattern, it’s

various implementation and Applicability.

I have tried my best to explain the concept in very simple language.

The programming language used for implementation is c#. But any one from

different programming background can easily understand the implementation.

Page 3: Factory method pattern (Virtual Constructor)

Definition

The factory method pattern is a design pattern that define an interface for

creating an object from one among a set of classes based on some logic.

Factory method pattern is a creational design pattern.

Factory method pattern is also known as virtual constructor pattern.

Factory method pattern is the most widely used pattern in the software

engineering world

Page 4: Factory method pattern (Virtual Constructor)

Motivation and Intent

• Creates objects without exposing the instantiation logic to the client.

• Refers to the newly created object through a common interface

At times, application only knows about the super class (may be abstract class),

but doesn’t know which sub class (concrete implementation) to be instantiated at

compile time.

Choice of sub class may be based on factors like:

• Application configuration.

• Expansion of requirements or enhancements.

• The state of the application running.

Page 5: Factory method pattern (Virtual Constructor)

Structure

Client

Concrete ProductA

<< interface >>

Product

Concrete ProductB+CreateProduct(): Product

Factory

Ask for a new ProductClient uses Product

Inheritance

Page 6: Factory method pattern (Virtual Constructor)

Implementation (C#)

Product product = new Product()

When we are using “new” keyword in C#, It allocates the

memory and creates a object of specified type.

This will be ok if we are having only one type of product

and a concrete class named “Product”.

But if we are having more than one product type, we can

create our “Product” as interface and provide various

implementation to it. Let the classes providing

implementation to our “Product” interface are “ProductA”

and “ProductB”. But now for Instantiating “Product” we

need to call the constructor of “Product” implementation.

But here Product type specified is fixed (hard-coded).

Let’s try for some generic implementation for this

scenario.

Product productA = new ProductA();

Product productB = new ProductB();

Page 7: Factory method pattern (Virtual Constructor)

Implementation (C#) Here function “CreateProduct” provide us a

generic implementation of our scenario.

“CreateProduct” function takes argument as

“string productType” and returns a object of

“ProductA” or “ProductB” based on the

condition and now we can call this function

with particular type of product and we will

get the object.

Although the code shown is far from

perfection like:

• Argument “string productType” can be

replaced by an “enum”.

• “if else” condition can be replaced by

“switch case” statements … etc.

But we can call our function “CreateProduct”

as a factory.

Let’s try to explore a better factory for our

product.

public Product CreateProduct(string productType)

{

Product product = null;

if (productType.Equals("ProductA"))

{

product = new ProductA();

}

else if (productType.Equals("ProductB"))

{

product = new ProductB();

}

return product;

}

Client:

Product productA = CreateProduct(“ProductA”);

Product productB = CreateProduct(“ProductB”);

Page 8: Factory method pattern (Virtual Constructor)

Implementation (C#)

Instead of function “CreateProduct” we

can have a class “ProductFactory” which

will help us in creating product and

provide a better control (class can have

helper function for product like packaging

etc.) on creation of product.

class ProductFactory {

public Product CreateProduct(string productType) {

Product product = null;

if (productType.Equals("ProductA")) {

product = new ProductA();

}

else if (productType.Equals("ProductB")){

product = new ProductB();

}

return product;

}

}

Client:

ProductFactory factory = new ProductFactory();

factory.CreateProduct(“ProductA”);

factory.CreateProduct(“ProductB”);

Page 9: Factory method pattern (Virtual Constructor)

Implementation (C#)Modified our “ProductFactory” class

by adding a “enum ProductType”

and added “switch” statement

instead of “If-else”.

Now our “ProductFactory” is good

to go.

If user is adding a new “ProductC”

in its product range, he a has to

define a new implementation to

Product interface (class

“ProductC”), Need to make changes

for “ProductC” in enum

“ProductType” and need to add a

switch case in our

“ProductFactory.CreateProduct”.

class ProductFactory {

public Product CreateProduct(ProductType productType) {

Product product = null;

switch(productType) {

case ProductType.ProductA:

product = new ProductA();

break;

case ProductType.ProductB:

product = new ProductB();

break;

default:

product = null;

break;

}

return product;

}

}

Client:

ProductFactory factory = new ProductFactory();

factory.CreateProduct(ProductType.ProductA);

factory.CreateProduct(ProductType.ProductB);

enum ProductType {

ProductA, ProductB,

};

Page 10: Factory method pattern (Virtual Constructor)

Options for adding new class without change in factory (C#)

If user is adding a new product in his product range he has to modify his “ProductFactory”. To

solve this problem we need a mechanism where “ProductFactory” is always aware of supported

Product types.

There can be two possible ways to achieve this solution:

• Using reflection (C#/Java).

• Without reflection (C++/C#/Java)

Page 11: Factory method pattern (Virtual Constructor)

Factory using reflection (C#)public enum ProductType : int {

ProductA = 1,

ProductB,

};

[AttributeUsage(AttributeTargets.Class)]

public class ProductAttribute : Attribute {

private ProductType mProductType;

public ProductAttribute(ProductType vProductType) {

mProductType = vProductType;

}

public ProductType ProductSupported {

get {

return mProductType;

}

set {

mProductType = value;

}

}

}

Page 12: Factory method pattern (Virtual Constructor)

Factory using reflection continue ….[AttributeUsage(AttributeTargets.Interface)]

public class ImplAttr : Attribute {

private Type[] mImplementorList;

public ImplAttr(Type[] Implementors) {

mImplementorList = Implementors;

}

public Type[] ImplementorList {

get {

return mImplementorList;

}

set {

mImplementorList = value;

}

}

}

Page 13: Factory method pattern (Virtual Constructor)

Factory using reflection continue ….[ImplAttr(new Type[] { typeof(ProductA), typeof(ProductB)})]

interface Product {

void Print();

}

[ProductAttribute(ProductType.ProductA)]

class ProductA : Product {

public void Print() {

Console.WriteLine("I am ProductA");

}

}

[ProductAttribute(ProductType.ProductB)]

class ProductB : Product {

public void Print() {

Console.WriteLine("I am ProductB");

}

}

Page 14: Factory method pattern (Virtual Constructor)

Factory using reflection continue ….class ProductFactory {

public Product CreateProduct(ProductType vProductType)

{

Product product = null;

object Obj;

Type[] IntrfaceImpl;

Attribute Attr;

ProductType productType;

ProductAttribute productAttr;

int ImplementorCount;

Attr = Attribute.GetCustomAttribute(typeof(Product), typeof(ImplAttr));

IntrfaceImpl = ((ImplAttr)Attr).ImplementorList;

ImplementorCount = IntrfaceImpl.GetLength(0);

for (int i = 0; i < ImplementorCount; i++) {

Attr = Attribute.GetCustomAttribute(IntrfaceImpl[i], typeof(ProductAttribute));

productAttr = (ProductAttribute)Attr;

Page 15: Factory method pattern (Virtual Constructor)

Factory using reflection continue ….

productType = productAttr.ProductSupported;

if ((int)productType == (int)vProductType) {

Obj = Activator.CreateInstance(IntrfaceImpl[i]);

product = (Product)Obj;

break;

}

}

return product;

}

}

Page 16: Factory method pattern (Virtual Constructor)

Factory using reflection continue ….

class Client

{

static void Main(string[] args)

{

ProductFactory factory = new ProductFactory();

Product product = factory.CreateProduct(ProductType.ProductA);

product.Print();

}

}

In the above mentioned code, we are having a factory which will remain unchanged even when user

is adding in product classes (new implementation of Product Interface) in his product range. In the

above implementation we have used reflection to achieve our objective.

Page 17: Factory method pattern (Virtual Constructor)

Factory without reflectionclass ProductFactory {

private static Dictionary<string, Product> registeredProducts = new Dictionary<string,Product>();

private static ProductFactory factoryInstance = new ProductFactory();

private ProductFactory() {

}

public static ProductFactory Instance {

get {

return factoryInstance;

}

}

public void registerProduct(String productID, Product p) {

registeredProducts.Add(productID, p);

}

Page 18: Factory method pattern (Virtual Constructor)

Factory without reflection continue ….public Product createProduct(String productID) {

Product product = null;

if (registeredProducts.ContainsKey(productID)) {

product = (Product)registeredProducts[productID];

}

return product;

}

}

Page 19: Factory method pattern (Virtual Constructor)

Factory without reflection continue ….interface Product {

void Print();

}

class ProductA: Product {

public static void RegisterID(string id) {

ProductFactory.Instance.registerProduct(id, new ProductA());

}

public void Print() {

System.Console.WriteLine("I am ProductA");

}

}

class ProductB : Product {

public static void RegisterID(string id) {

ProductFactory.Instance.registerProduct(id, new ProductB());

}

public void Print() {

System.Console.WriteLine("I am ProductB");

}

}

Page 20: Factory method pattern (Virtual Constructor)

Factory without reflection continue ….class Client {

static void Main(string[] args) {

ProductFactory factory = ProductFactory.Instance;

ProductA.RegisterID("ProductA");

Product productA = factory.createProduct("ProductA");

((ProductA)productA).Print();

ProductB.RegisterID("ProductB");

Product productB = factory.createProduct("ProductB");

((ProductB)productB).Print();

}

}

In the above mentioned code, we are having a factory which will remain unchanged even when user

is adding in product classes (new implementation of Product Interface) in his product range. The

above implementation is achieved without reflection. In the above implementation the

“ProductFactory” class is created as singleton.

Page 21: Factory method pattern (Virtual Constructor)

End of Presentation . . .