Factory Pattern: Motivation • Consider the Following Scenario: – You Have

Factory Pattern: Motivation • Consider the Following Scenario: – You Have

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 • Class diagram: • 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 Factory Method Pattern 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

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    23 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us