0

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?

  • 2
    The 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 Jun 21 '17 at 21:06
-2

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 instantiate Foo by implementing new FooFactorys.
  • Adds an abstraction layer that decouples and improves testability
  • 2
    Ack... Really? .... – Robert Harvey Jun 21 '17 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 Jun 21 '17 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 Jun 21 '17 at 22:18
  • 1
    All in all, it seems like a lot of boilerplate for dubious benefits. – Robert Harvey Jun 21 '17 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 Jun 21 '17 at 23:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.