I'm trying to write an Entity-Component System and I want to have different factories creating different kinds of entities. For example the HumanEntityFactory class will create human entities.
Would it break separation of concerns if I store the different types of human that the factory can create, or should I create a factory for each kind of human?
HumanEntityFactory
===========
-HashMap<String, Component[]> humanEntityTypeComponents
+addHumanType(String typeName, Component[] components)
+createHuman(String type)
Entity
======
-HashMap<String, Component> components
-
1It's unclear from your question whether "human type" is an entity in its own right, or whether it is merely a property of "human." Also, Separation of Concerns doesn't mean what you think it means.Robert Harvey– Robert Harvey2017年12月03日 17:58:04 +00:00Commented Dec 3, 2017 at 17:58
-
"human type" are common properties for different kinds of human, for example the maximum speed of human child might be A, whereas the maximum speed of a HumanSprinter might be B.HermanTheGermanHesse– HermanTheGermanHesse2017年12月03日 18:01:33 +00:00Commented Dec 3, 2017 at 18:01
-
1If you're using a factory for storage you haven't built a factory. You've built a repository. Factories make things.candied_orange– candied_orange2017年12月03日 21:16:53 +00:00Commented Dec 3, 2017 at 21:16
-
It also creates the humans of the certain types... Does this violate SRP?HermanTheGermanHesse– HermanTheGermanHesse2017年12月03日 21:20:13 +00:00Commented Dec 3, 2017 at 21:20
-
SRP doesn't mean what you think it means either.Robert Harvey– Robert Harvey2017年12月03日 23:25:21 +00:00Commented Dec 3, 2017 at 23:25
1 Answer 1
First, it is important to make a difference between Single Responsibility Principle (SRP, related to Clean Code) and Separation of Concerns (SOC, related to engineering at large).
Analyse of your design
The Entity-Component-System has the purpose of avoiding a rigid compile-time class hierarchy by using a flexible data structure based on a flat Entity type enriched through run-time composition with components.
I understand that:
- your
HumanEntityFactory
creates humanEntities
of different kind, each kind being characterized by a different set of defaultComponents
. - in order to keep the system flexible, you define at run-time the standard components to use for each kind of human (e.g.
addHumanType("Warrior", { new Sword(), new WarriorRenderer() })
) - then a new human is instantiated by the factory with the method
createHuman()
(e.g.createHuman("Warrior")
,createHuman("Magician")
and so on). I'll assume that the standard components are cloned, in case they have a state (e.g.defensivePower
,offensivePower
,depreciation
).
Single responsibility
The name of this principle is somewhat misleading. So let's look at R.C.Martin's own explanations: SRP is about reasons to change, which are in general related to people responsibilities.
What are the possible changes that may require a change of the factory ?
- change of the Entity interface. That's natural because we factor Entities.
- change the Component creation logic. Someone may for example change the way the Components are created, moving from cloning to a factory.
- change of the way the kinds of humans are managed, together with their component "templates".
I see here 3 different reasons for change, so no, it's not compliant with the SRP.
Note that having more "templates", i.e. more kinds of humans, will not require any changes to the factory class. So this is not relevant for SRP.
Separation of concerns
The separation of concerns is about modularity and decoupling. Your factory class seems to addresses two distinct concerns:
- First, it manages the human types (via the method
addHumanType()
and the propertyhumanEntityTypeComponents
). - Then, it creates a new Entity according to the configuration
The first concern, is something that is related to the configuration. You certainly do this during the initialization, and probably it's the consequence of loading some configuration file. The second concern is unrelated.
So this design does not respect the separation of concerns either.
Way forward
The first thing would be to have a class managing the configuration of human entities.
The second thing would be to have a generator class, that generates a list of components for a given kind, based on the configuration.
The entity factory could then be instantiated by injecting the configuration and the generator,