0

The factory method is used to avoid violation of Open-closed principle. Instead of creating an object by inheritage:

Product myProd = new ConcreteProduct1; // concreteProduct extends abstract product
myProd.doSomething();

we use a factory "interface" with relatives concrete factories (classes that implement factory and overrride its methods):

Factory myFact = new ConcreteFact1; // (2)
Product myProd = myFact.createProd();   // (1)
myProd.doSomething(); // (1)

I read much about factory method; I understood that, using factory method, it's possible to exclude vilations of the open-closed principle. But I still don't understand:

  1. with this design pattern we have still a dependency to class Product (myProd) (1)
  2. moreover.. we have a dependency with Concrete-Factories (client needs to instantiate a specific wanted concrete factory and client must know witch one) (2)

Tank you for any clarification.

Marco
  • 133
  • 2
  • 13
  • 1
    You use the Factory the wrong way. Factories normally have static methods which provide the "product". But in your code at (2) you use myFact without even using it. – Christian Feb 16 '18 at 12:28
  • I did a mistake, code updated. – Marco Feb 16 '18 at 12:32

2 Answers2

1
  1. We do have a dependency on Product, but the point is to eliminate the dependency on ConcreteProduct.

  2. No, we don't have a dependency on ConcreteFactory because we get passed the factory as a parameter.

    class MassProduction {
        ProductFactory factory;
        public MyClass(ProductFactory fact) {
           factory = fac;
        }
        public List<Product> produce(int amount) {
            ArrayList<Product> result = new ArrayList<>(amount);
            for (int i = 0; i < amount; i++) { 
                result.add(factory.createProduct());
            }
            return result;
        }
    }
    

At no point do we have a dependency on either ConcreteProduct or ConcreteFactory.

daniu
  • 14,137
  • 4
  • 32
  • 53
  • Tank you for this fantastic example, I ask you last clarification: client that call MassProduction.MyClass(fact) must be aware about ConcreteFactories (witch fact). There is a way to avoid this? tank you – Marco Feb 16 '18 at 12:48
  • @Marco Well yes, someone does have to pass a concrete class eventually of course, but only at the very end. The point is, that client will be able to use the `MassProduction` facility without the `MassProduction` knowing about the client's `Product`. – daniu Feb 16 '18 at 12:53
  • Before I had: Factory myFact = new ConcreteFact1 now I have: Factory myfactory = new MassProduct; myfactory.myClass(new ConcreteFactory1()); it's quite a mistery for me.. – Marco Feb 16 '18 at 14:21
1

You might not exactly in a position needing to use the whole concept.

Here's a use case:

// define the interfaces
public interface Product {}
public interface ProductFactory {
    public Product createProduct();
}
// create some implementors
public class Sweatshirt implements Product {
    static final ProductFactory FACTORY = new ProductFactory() {
        public Product createProduct() {
            return new Sweatshirt();
        }
    }
}
public class Pants implements Product {
    static final ProductFactory FACTORY = new ProductFactory() {
        public Product createProduct() {
            return new Pants();
        }
    }
}
public class Hat implements Product {
    static final ProductFactory FACTORY = new ProductFactory() {
        public Product createProduct() {
            return new Hat();
        }
    }
}

// create a client class
class Stock {
    private List<? extends Product> stock = new ArrayList<>();
    public void add(int amount, ProductFactory fac) {
        for (int i = 0; i < amount; i++) {
            stock.add(fac.createProduct());
        }
    }
    public void printAll() {
        stock.forEach(p -> System.out.println(p.getClass()));
    }
}

// driver class that allows the user to enter amounts and product type
// and adds them to the stock until any entry is invalid
class InventoryManagement {
    public static void main(String[] args) {
        Stock stock = new Stock();
        try (Scanner sc = new Scanner(System.in)) {
            while (true) {
                // read amount from console input
                int amount = sc.nextInt();
                // read type from console input
                String value = sc.next();
                ProductFactory factory = null;
                switch(value) {
                    case "s":
                         factory = Sweatshirt.FACTORY;
                         break;
                    case "p":
                         factory = Pants.FACTORY;
                         break;
                    case "h":
                         factory = Hat.FACTORY;
                         break;
                 }
                 if (factory != null) {
                     stock.add(amount, factory);
                 } else {
                     break;
                 }
            }
        } catch (Exception e) {} 
        stock.printAll();
    }
}

As you can see, the client class (Stock) doesn't have any references to any concrete Product or Factory, but it uses the given Factorys to create Products. It's the driver class that connects the two (the client class Stock and the concrete products).

daniu
  • 14,137
  • 4
  • 32
  • 53
  • Tank you for help, but I still don't understand: now the situation is get back.. in static main we have again a direct dependency to concreteProducts. (and we need to import relative classes) – Marco Feb 22 '18 at 13:13
  • static main is your _main program_... you will have to have actual products eventually, and your main is the last possible point in time. I guess you could construct product factories generically, as in load from a database without an actual class being referenced, but how to do that is a different question. – daniu Feb 22 '18 at 13:38
  • I tried to explain that using factories in Stock class you depend from concreteProducts,as it was in the first case (polymorphism). what's the difference? – Marco Feb 22 '18 at 14:58
  • You don't depend on concrete products in `Stock`, only in main. Your `Stock` is reusable for any kind of product, as long as you have a factory for it. That means you can reuse your `Stock` class for another program with another main method adding different products (eg `Yoghurt`, `IceCream`, `Jello`) by providing factories for them. – daniu Feb 22 '18 at 15:17
  • Ok, in main.. but we started using factory method because of "problem of creating objects without having to specify the exact class of the object that will be created"(wikipedia). now, in main, we must specify (call, import, use..) them again... – Marco Feb 22 '18 at 16:15