Factory Pattern: Motivation • Consider the following scenario: – You have a superclass (P roduct) and a set of subclasses that inherit from it (P roductSubclass1, P roductSubclass2, ...) – As usual, there are a number of methods that the subclasses share in com- mon, that they inherit from the superclass – You have client code that needs to be able to create objects of the various subclasses ∗ We’ll call this the orderProduct method ∗ We’ll refer to the created objects as products ∗ To specify to which subclass a product should belong, orderProduct will have a parameter which specifies the type

1 Factory Pattern: Motivation (2) – For example: public class Product { //constructor

...

... step1(...) { //Methods that apply to all subclasses in common ... }

... step2(...) { ... } ...

}

public class ProductSubclass1 extends Product { ... }

public class ProductSubclass2 extends Product { ... }

public class ProductClient { ...

Product orderProduct (String type) { Product product;

if (type.equals("subclass1")) product = new ProductSubclass1(); else if (type.equals("subclass2")) product = new ProductSubclass2(); ...

product.step1(); product.step2(); ... return product; } ...

} • The problem with this approach - as usual - is limited flexibility – If we want to add new subclasses - types of products - (or remove existing ones), the client’s code must be altered – The above design violates the Open/Closed Principle, among others

2 Factory Pattern: The Simple Factory Model • We want to encapsulate what varies – The part that varies is the product creation - We want to encapsulate the code that creates new products – To accomplish this, we’ll create a new class that we’ll call a factory – It’s purpose is to create new products of a desired type – The client will have an instance variable for the factory ∗ The factory will be used from within the orderP roduct method of the client to create products

3 Factory Pattern: The Simple Factory Model (2) • Sample code:

//Superclass and subclasses as before

public class ProductSubclass1 extends Product { ...

}

public class ProductSubclass2 extends Product { ...

}

public class SimpleFactory {

public Product createSubclassProduct (String type) { Product product null;

if (type.equals("subclass1")) product = new ProductSubclass1(); else if (type.equals("subclass2")) product = new ProductSubclass2(); ...

return product; }

public class Client { SimpleFactory factory;

public Client (SimpleFactory factory) { this.factory = factory;) }

Product orderProduct (String type) { Product product;

product = factory.createSubclassProduct(type); product.step1(); product.step2(); ...

return product; } ...

}

4 Factory Pattern: The Simple Factory Model (3)

• Summary of the changes: 1. Create a new factory class – The factory implements the method for creating new products – This code had originally been in the client 2. Remove the product creation method from the client – Replace it with a call to the product creation method in the factory 3. Add an instance variable for the factory in the client – Its value is passed in via the constructor • :

• Simple Factory is not a true pattern

5 Factory Pattern: Further Considerations • Suppose you now want to have different types of clients – Each client type produces the same set of products, but – Each product of a given subclass varies in some way from client type to client type • We can think of each client type as representing a category for the subclasses – For example , there is a 1. A category1 for ProductSubclass1, ProductSubclass2, ...; 2. A category2 for ProductSubclass1, ProductSubclass2, ..., etc. ∗ Each category makes products for the same set of subclasses ∗ But each category produces them with slightly different characteristics – For the subclasses, some inherited methods may be implemented exactly the same no matter what category a product belongs to – Other methods may differ based on the category of the product**** • One approach would be to have a factory for each category – A factory for category1 – A factory for category2 – ...

6 Factory Pattern: Further Considerations (2)

• Class diagram:

• Sample driver code:

Category1Factory factory1 = new Category1Factory(); Client cat1Client = new Client(factory1); cat1Client.orderProduct("class1");

Category2Factory factory2 = new Category2Factory(); Client cat2Client = new Client(factory2); cat2Client.orderProduct("class1");

7 Factory Pattern: Further Considerations (3) – In the above example ∗ Two factories are created: 1. One for creating category1 products 2. One for creating category2 products ∗ Two objects are created: 1. cat1Client, which ”orders” class1-type products from a category1 fac- tory 2. cat2Client, which ”orders” class1-type products from a category2 fac- tory ∗ Both clients end up with class1 products, but they differ as per the category to which they belong • A better approach would be to link the product creation back to the client, but with more flexibility than our original approach had – To achieve the flexibilty of having product creation back in the client: 1. Make an abstract class for clients (Client) 2. Move the createP roduct method back into the Client class ∗ This method becomes abstract here ∗ With the createP roduct back in the Client class, Client becomes a superclass for factories 3. Make a client subclass for each category (Category1F actory, Category2F actory, ...) ∗ These subclasses inherit from Client ∗ Since createP roduct is abstract in Client, each of these subclasses must implement it ∗ These implementations will reflect the variations peculiar to the cat- egory ∗ The subclasses are the actual factories 4. We still have a generic P roduct class 5. Create a subclass for each combination of product subclass and category ∗ The subclasses all inherit from the P roduct class

8 Factory Pattern: Further Considerations (4) – Class diagram:

9 Factory Pattern: Further Considerations (5) – Code: public abstract class Client {

public Product orderProduct(String type) {

Product product;

product = createProduct(type);

product.step1(...); product.step2(...); ...

return product; }

abstract Product createProduct(String type); }

public abstract class Product {

... step1(...) { //Methods that apply to all subclasses in common ... }

... step2(...) { ... } ...

}

public class Category1Factory extends Client { ...

Product createProduct (String type) {

if (type.equals("subclass1")) return new Category1Subclass1Product(); else if (type.equals("subclass2")) return new Category1Subclass2Product(); ... else return null; } ...

}

10 Factory Pattern: Further Considerations (6) public class Category1Subclass1Product extends Product { //constructor

//Override any steps that are specific to Catgory1Subclass1 products

... } public class Driver {

public static void main (String[] arge) { Client cat1Factory = new Category1Factory(); Client cat2Factory = new category2Factory();

Product product = cat1Factory.orderProduct("type2"); product = cat2Factory.orderProduct("type2"); ... }

11 Factory Pattern: The Defined • The Factory Pattern (p 134): Defines an interface for creating an object, but lets subclasses decide which class to instantiate. Factory Method lets a class defer instantia- tion to subclasses. • Class diagram:

• The pattern encapsulates the instantiation of concrete types 1. The Creator class provides an interface for creating products – It defines the factory structure 2. The concrete subclasses of Creator actually generate the products 3. Methods in Creator other than factoryMethod are used only to operate on the products • ”Deciding by subclasses” is a bit misleading – It’s the user/programer who actually decides what subclass will be instan- tiated – The use of ”decides” is meant to imply loose coupling between the client and Creator – Creator doesn’t know what products are being created

12 Factory Pattern: The Factory Method Pattern Defined (2)

• Even when only a single concrete creator is needed, the Factory Method is warranted – It decouples the implementation of a product from its use – It facilitates addition of additional concrete creators – It facilitates modification of implementation • While similar to the Simple Factory, Factory is different – In Simple Factory, the factory is composed with the client – In Factory, each client must implement the factory method • Creator and factoryMethod can be concrete – This allows creation of products even when there are no subclasses • There can be a single type of product rather than variations (types) – In such cases, no parameter needs to be passed to the factory method

13 Factory Pattern: Dependency Inversion Principle • The Dependency Inversion Principle (p 139) (Principle 6) Depend upon abstractions. Do not depend upon concrete classes. • It imposes a stricter condition than the ”Program to an interface, not an im- plementation” Principle – High-level components should not depend on low-level ones – Both should depend on abstractions – This is an ”inversion” of the usual type of thinking in OO design • In our original approach (Factory Pattern Motivation), if we had taken into account categories of products, we would have ended up with code similar to

public class Client {

public Product createProduct (String category, String type) { Product product = null; if (category.equals("category1")) if (type.equals("type1")) product = new Category1Subclass1(); else if (type.equals("type2")) product = new Category1Subclass2(); ... if (category.equals("category2")) if (type.equals("type1")) product = new Category2Subclass1(); else if (type.equals("type2")) product = new Category2Subclass2(); ...... } step1(); step2(); ... }

14 Factory Pattern: Dependency Inversion Principle (2)

• Class diagram:

• This violates the Inversion Principle

15 Factory Pattern: Dependency Inversion Principle (3)

• A reworking (as in our refinement) that conforms to the principle would look like this

• Guidelines for designing to this principle: 1. No variable should hold a reference to a concrete class 2. No class should derive from a concrete class 3. No method should override an implemented method of any of its base classes

16 Factory Pattern: Motivation • Consider an extension to our original problem – Suppose that in addition to having different categories for our products, some categories build a given subclass with different ingredients – I.e., we now have families of ingredients • To handle this, we can use ingredient factories – We’ll use an interface for the ingredient factory ∗ An ingredient factory creates all ingredients needed for the product – We’ll need a class for each of the ingredients – We’ll use concrete factories for each category of ingredients – In the constructor for a (product) category class, pass in the type of product to be instantiated (as usual) – In the constructor for a product class, pass in an ingredient factory to be used for the ingredients for the product – In the product interface, the prepare method becomes abstract – The product subclasses implement the prepare method using the ingredient factory passed to them – Product factories instantiate an ingredient factory of the appropriate type to be passed to the product’s constructor

17 Factory Pattern: Abstract Factory Pattern Description (2) • Code:

public interface ProductIngredientFactory {

public Ingredient1 createIngredient1(); public Ingredient2 createIngredient2(); ... }

public Category1IngredientFactory implements ProductIngredientFactory { public Ingredient1 createIngredient1() { create new someKindOfIngredient1(); }

public Ingredient2 createIngredient2() { create new someKindOfIngredient2(); }

... }

public abstract class Product { Ingredient1 ingredient1; Ingredient2 ingredient2; ...

abstract void prepare(); //implemented by subclasses, which use appropriate ingredients

... step1(...) { //Methods that apply to all subclasses in common ... }

... step2(...) { ... } ...

}

public class ProductSubclass1 extends Product { ProductIngredientFactory productIngredientFactory;

public ProductSubclass1 (ProductIngredientFactory productIngredientFactory) { this.productIngredientFactory = ProductIngredientFactory; ... }

void prepare () { ingredient1 = productIngredientFactory.createIngredient1(); ingredient2 = productIngredientFactory.createIngredient2(); ... } }

18 Factory Pattern: Abstract Factory Pattern Description (3) public class ProductSubclass2 extends Product { ProductIngredientFactory productIngredientFactory;

public ProductSubclass2 (ProductIngredientFactory productIngredientFactory) { this.productIngredientFactory = ProductIngredientFactory; ... }

void prepare () { ingredient1 = productIngredientFactory.createIngredient1(); ingredient2 = productIngredientFactory.createIngredient2(); ... } } public abstract class Client {

public Product orderProduct(String type) {

Product product;

product = createProduct(type);

product.step1(...); product.step2(...); ...

return product; }

abstract Product createProduct(String type); }

19 Factory Pattern: Abstract Factory Pattern Description (4) public class Category1Client extends Client { ...

protected Product createProduct (String type) { //New composition of ingredient factory ProductIngredientFactory productIngredientFactory = new Category1IngredientFactory();

if (type.equals("subclass1")) return new Category1Subclass1Product(ingredientFactory); //New ingredient factory parameter else if (type.equals("subclass2")) return new Category1Subclass2Product(ingredientFactory); ... else return null; } ...

} public class Category1Subclass1Product extends Product { //constructor

//Override any steps that are specific to Catgory1Subclass1 products

... } public class Driver {

public static void main (String[] arge) { Client cat1Client = new Category1Client(); Client cat2Client = new category2Client();

Product product = cat1Client.orderProduct("type2"); product = cat2Client.orderProduct("type2"); ... }

20 Factory Pattern: Abstract Factory Defined • Abstract Factory (p 156): Provides an interface for creating families of related or dependent objects without specifying their concrete classes. • Class diagram:

21 22 Factory Pattern: Abstract Factory Defined (2)

• The factory decouples the client from the concrete product factories • This allows substitution of factories to get different behaviors • The concrete factories make the same products - they’re just implemented differently

23