pros and cons of using factory vs regular constructor
The GRASP design principles provide guidelines for assigning responsibility to classes and objects in object-oriented design. For example, the Creator pattern suggests: In general, a class B should be responsible for creating instances of class A if one, or preferably more, of the following apply:
- Instances of B contains or compositely aggregates instances of A
- Instances of B record instances of A
- Instances of B closely use instances of A
- Instances of B have the initializing information for instances of A and pass it on creation.
In your example, you have complicated and evolving code for applying rules to data. That suggests the use of the Factory Pattern.
Putting the code in Results is contraindicated because 1) results don't create results, and 2) results aren't the information expert (i.e. they don't have most of the knowledge that is needed).
In short, the ResultFactory seems like a reasonable place to concentrate the knowledge of how to apply rules to data to generate results. If you were to try to push all of this logic into class constructors for either Results or Rules, it would lead to tight coupling and loss of cohesion.
Third scenario:
You may want to consider a third scenario:
- Put the code inside the method
Rules.__call__
.
InstantiatingResult
like:result = rules(data)
Pros:
Result
s can be totally unaware of theRules
that generates them (and maybe even of the originalData
).- Every
Rules
sub-class can customize itsResult
creation. - It feels natural (to me):
Rules
applied toData
yieldResult
. - And you'll have a couple of GRASP principle on your side:
- Creator: Instances of
Rules
have the initializing information for instances ofResult
and pass it on creation. - Information Expert: Information Expert will lead to placing the responsibility on the class with the most information required to fulfill it.
- Creator: Instances of
Side effects:
- Coupling: You'll raise the coupling between
Rules
andData
:- You need to pass the whole data set to every
Rules
- Which means that each
Rules
should be able to decide on which data it'll be applied.
- You need to pass the whole data set to every