I have a class in python that is instantiated from the values of a (json) config file. I was wondering what is the best practise to do that (if there is a best practise and is not just a matter of personal preference).
- I call a read_config function (which is defined outside the class) in my main, that parses my configuration file and returns the configuration as a dictionary. Then, I instantiate the class using this dictionary.
or
- I instantiate the class by giving the configuration file name. In my class there is the read_config method that sets my instance variables.
In the first method I find positive that I am a little bit more flexible from where I get my config data. It could be a file, or even a hard-coded dictionary. Is there any software design rule that should be followed or it really doesn't matter?
-
2The most relevant principle at play here is probably "Single Responsibility." You will have to decide if it's your class' responsibility to parse JSON. Normally that parsing would take place somewhere else, and you would pass the result of that parse (i.e. a DTO) to your class being configured. A dictionary also works.Robert Harvey– Robert Harvey2017年06月21日 21:06:40 +00:00Commented Jun 21, 2017 at 21:06
1 Answer 1
The design pattern for constructing objects is called the factory pattern.
My suggestion is you create an abstract factory that takes the parsed dictionary and returns the instantiated object (in fp pseudocode):
// FooFactory is a function that takes a dictionary and produces a Foo
FooFactory = Dict => Foo
def defaultFooFactory(dict: Dict): Foo
// from dict
return Foo(...)
To address where the JSON file should be parsed, you can implement FooFactory
for that:
def jsonFooFactory(fileName: String, delegate: FooFactory)(dict: Map[String, Object]): Foo =
// load json file from fileName and merge it with passed dict
combinedDict = ...
return delegate(combinedDict)
Then at your composition root you should construct your chosen factory:
factory = jsonFooFactory("config.json", defaultFooFactory)
You can pass around your factory and create instances of Foo
whenever you want:
factory(// overrides to json could be passed here)
The benefits of this pattern are:
- Follows single responsibility principle. A class shouldn't know how to instantiate itself
- Abstracts the construction of
Foo
. You can change how you instantiateFoo
by implementing newFooFactory
s. - Adds an abstraction layer that decouples and improves testability
-
2Ack... Really? ....Robert Harvey– Robert Harvey2017年06月21日 22:06:40 +00:00Commented Jun 21, 2017 at 22:06
-
4
Follows single responsibility principle. A class shouldn't know how to instantiate itself
-- That's not what SRP means. This is probably where your answer runs off the rails.Robert Harvey– Robert Harvey2017年06月21日 22:16:48 +00:00Commented Jun 21, 2017 at 22:16 -
1
Abstracts the construction of Foo. You can change how you instantiate Foo by implementing new FooFactorys
-- Again, why would you need this? A dictionary provides more than sufficient abstraction for a general-purpose configuration mechanism.Robert Harvey– Robert Harvey2017年06月21日 22:18:06 +00:00Commented Jun 21, 2017 at 22:18 -
1All in all, it seems like a lot of boilerplate for dubious benefits.Robert Harvey– Robert Harvey2017年06月21日 22:21:01 +00:00Commented Jun 21, 2017 at 22:21
-
2" SRP says that a class should only have one reason to change. If Foo knows how to instantiate itself then it will have two reasons to change-- 1. if Foo's logic changes and 2. if Foo's instantiation changes." sweet jesus, by that logic every single class needs a factory, every factory needs a factoryfactory, etc.whatsisname– whatsisname2017年06月21日 23:55:35 +00:00Commented Jun 21, 2017 at 23:55
Explore related questions
See similar questions with these tags.