|
| 1 | +# When To Use Factories vs Abstract Factories |
| 2 | + |
| 3 | +Starting with version 3, `Zend\ServiceManager\Factory\AbstractFactoryInterface` |
| 4 | +extends `Zend\ServiceManager\Factory\FactoryInterface`, meaning they may be used |
| 5 | +as either an abstract factory, or mapped to a specific service name as its |
| 6 | +factory. |
| 7 | + |
| 8 | +As an example: |
| 9 | + |
| 10 | +```php |
| 11 | +return [ |
| 12 | + 'factories' => [ |
| 13 | + SomeService::class => AnAbstractFactory::class, |
| 14 | + ], |
| 15 | +]; |
| 16 | +``` |
| 17 | + |
| 18 | +Why would you choose one approach over the other? |
| 19 | + |
| 20 | +## Comparisons |
| 21 | + |
| 22 | +Approach | Pros | Cons |
| 23 | +---------------- | -------------- | ---- |
| 24 | +Abstract factory | One-time setup | Performance; discovery of code responsible for creating instance |
| 25 | +Factory | Performance; explicit mapping to factory responsible | Additional (duplicate) setup |
| 26 | + |
| 27 | +Essentially, it comes down to *convenience* versus *explicitness* and/or |
| 28 | +*performance*. |
| 29 | + |
| 30 | +## Convenience |
| 31 | + |
| 32 | +Writing a factory per service is time consuming, and, particularly in early |
| 33 | +stages of an application, can distract from the actual business of writing the |
| 34 | +classes and implementations; in addition, since requirements are often changing |
| 35 | +regularly, this boiler-plate code can be a nuisance. |
| 36 | + |
| 37 | +In such situations, one or more abstract factories — such as the |
| 38 | +[ConfigAbstractFactory](../config-abstract-factory.md), the |
| 39 | +[ReflectionBasedAbstractFactory](../reflection-abstract-factory.md), or the |
| 40 | +[zend-mvc LazyControllerAbstractFactory](https://docs.zendframework.com/zend-mvc/cookbook/automating-controller-factories/) |
| 41 | +— that can handle the bulk of your needs are often worthwhile, saving you |
| 42 | +time and effort as you code. |
| 43 | + |
| 44 | +## Explicitness |
| 45 | + |
| 46 | +The drawback of abstract factories is that lookups by the service manager take |
| 47 | +longer, and increase based on the number of abstract factories in the system. |
| 48 | +The service manager is optimized to locate *factories*, as it can do an |
| 49 | +immediate hash table lookup; abstract factories involve: |
| 50 | + |
| 51 | +- Looping through each abstract factory |
| 52 | + - invoking its method for service location |
| 53 | + - if the service is located, using the factory |
| 54 | + |
| 55 | +This means, internally: |
| 56 | + |
| 57 | +- a hash table lookup (for the abstract factory) |
| 58 | +- invocation of 1:N methods for discovery |
| 59 | + - which may contain additional lookups and/or retrievals in the container |
| 60 | +- invocation of a factory method (assuming succesful lookup) |
| 61 | + |
| 62 | +As such, having an explicit map can aid performance dramatically. |
| 63 | + |
| 64 | +Additionally, having an explicit map can aid in understanding what class is |
| 65 | +responsible for initializing a given service. Without an explicit map, you need |
| 66 | +to identify all possible abstract factories, and determine which one is capable |
| 67 | +of handling the specific service; in some cases, multiple factories might be |
| 68 | +able to, which means you additionally need to know the *order* in which they |
| 69 | +will be queried. |
| 70 | + |
| 71 | +The primary drawback is that you also end up with potentially duplicate |
| 72 | +information in your configuration: |
| 73 | + |
| 74 | +- Multiple services mapped to the same factory. |
| 75 | +- In cases such as the `ConfigAbstractFactory`, additional configuration |
| 76 | + detailing how to create the service. |
| 77 | + |
| 78 | +## Tradeoffs |
| 79 | + |
| 80 | +What it comes down to is which development aspects your organization or project |
| 81 | +favor. Hopefully the above arguments detail what tradeoffs occur, so you may |
| 82 | +make an appropriate choice. |
| 83 | + |
| 84 | +## Tooling |
| 85 | + |
| 86 | +Starting with 3.2.0, we began offering a variety of [console tools](../console-tools.md) |
| 87 | +to assist you in generating both dependency configuration and factories. Use |
| 88 | +these to help your code evolve. An expected workflow in your application |
| 89 | +development evolution is: |
| 90 | + |
| 91 | +- Usage of the `ReflectionBasedAbstractFactory` as a "catch-all", so that you |
| 92 | + do not need to do any factory/dependency configuration immediately. |
| 93 | +- Usage of the `ConfigAbstractFactory`, mapped to services, once dependencies |
| 94 | + have settled, to disambiguate dependencies, or to list custom services |
| 95 | + returning scalar or array values. |
| 96 | +- Finally, usage of the `generate-factory-for-class` vendor binary to generate |
| 97 | + actual factory classes for your production-ready code, providing the best |
| 98 | + performance. |
0 commit comments