Skip to content
This repository was archived by the owner on Feb 6, 2020. It is now read-only.

Commit cd97cd1

Browse files
committed
Merge branch 'hotfix/148' into develop
Close #150 Fixes #148
2 parents 972b03b + e6d0c3e commit cd97cd1

File tree

3 files changed

+103
-0
lines changed

3 files changed

+103
-0
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ All notable changes to this project will be documented in this file, in reverse
3232
`config` service, if present.
3333
- All other array values will be provided an empty array.
3434
- Class/interface typehints will be pulled from the container.
35+
- [#150](https://github.com/zendframework/zend-servicemanager/pull/150) adds
36+
a "cookbook" section to the documentation, with an initial document detailing
37+
the pros and cons of abstract factory usage.
3538

3639
### Deprecated
3740

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
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.

mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ pages:
1111
- 'Configuration-based Abstract Factory': config-abstract-factory.md
1212
- 'Reflection-based Abstract Factory': reflection-abstract-factory.md
1313
- 'Console Tools': console-tools.md
14+
- Cookbook:
15+
- 'Factories vs Abstract Factories': cookbook/factories-vs-abstract-factories.md
1416
- 'Migration Guide': migration.md
1517
site_name: zend-servicemanager
1618
site_description: 'zend-servicemanager: factory-driven dependency injection container'

0 commit comments

Comments
 (0)