Is this a Simple Factory violation of the Open Closed principle?

Is this a simple factory violation of open closing?

SimpleProductFactory needs to be changed every time you need to create a new specific product, but it adheres to the principle of single responsibility, because this is the only reason why it will ever change. Its sole purpose is to ensure that the Client does not violate the open, closed principle, so I believe that this cannot be the violation itself, since, obviously, this code is needed somewhere.

I'm not interested in changing Factory, but whether this particular example is a violation or not.

product

interface Product{ public int getPrice(); } 

Milk

 class Milk implements Product{ public int getPrice(){ return 5; } } 

Crisps

 class Chips implements Product{ public int getPrice(){ return 3; } } 

SimpleProductFactory

 class SimpleProductFactory{ public Product createProduct(String productName){ if(productName.equals("milk")){ return new Milk(); } else if(productName.equals("chips")){ return new Chips(); } return null; } } 

Client

 class Client{ public static void main(String[] args) { SimpleProductFactory productFactory = new SimpleProductFactory(); Product prod = productFactory.createProduct("milk"); System.out.println(prod.getPrice()); } } 
+7
java oop design-patterns solid-principles design-principles
source share
4 answers

Is this a simple factory violation of open closing?

To answer your questions. "Yes, Simple Factory violates the principle of open closure for any reason ."

A simple Factory template that needs to be modified to help us choose a specific class for the caller. If we make this class conform to the open closed principle, we must transfer the load to some other class, and this class will no longer serve the purpose of the Factory. Not all principles are absolute. We need to weigh the benefits when using or not.

+2
source share

In addition to Timothy Truckle, answer about the service locator ...

In Java 8, you can use method references and Supplier to implement a common factory for such simple use cases as yours.

eg.

 class SimpleProductFactory { private Map<String, Supplier<? extends Product>> supplierRegistry = new HashMap<>(); public void addProductSupplier(String productName, Supplier<? extends Product> productSupplier) { supplierRegistry.put(productName, productSupplier); } public Product createProduct(String productName) { Product product = null; Supplier<? extends Product> productSupplier = supplierRegistry.get(productName); if (productSupplier != null) { product = productSupplier.get(); } return product; } } 

And your client code will look like this:

 class Client{ public static void main(String[] args) { SimpleProductFactory productFactory = new SimpleProductFactory(); productFactory.addProductSupplier("milk", Milk::new); // Constructor reference productFactory.addProductSupplier("chips", Chips::new); Product prod = productFactory.createProduct("milk"); System.out.println(prod.getPrice()); } } 

As you can see, a simple factory is

  • open for expansion because you can simply add other product suppliers.
  • closed for modification , because you do not need to change it, when another product is implemented, you just add it.

PS: With a little more refactoring, you can just turn it into a real general factory for any type.

+2
source share

The open / closed principle is really not applicable to factories, because they are still the source of different typed objects ...

On the other hand, you can have an abstract Factory search for real "factories" using javas ServiceLoader . Then you could add more real factories even to your own banks without changing the existing code ...

+1
source share

The static factory example above is still expanding for additional products such as Icecream as follows. Even if we make the static factory method immovable, it can be extended (although not by traditional method overrides)

  class SimpleProductFactoryExt extends SimpleProductFactory { public Product createProduct(String productName) { if (productName.equals("Icecream")) { return new Milk(); } else { return super.createProduct(productName); } } } 
0
source share

All Articles