Reputation: 9845
I have some classes that need to interact. Every class has many options that could be tuned to get one behaviour or another.
(note: I didn't test the code so there could be some syntax error)
(note 2: I write in PHP, but I guess the question is valid for every OOP language as well)
<?php
class Process
{
protected $element;
protected $config;
protected $default_config = array(
'process_path' => '/bin/command',
'default_output_path' => '/tmp/',
'element_conf' => array()
);
public function __construct(array $config)
{
$this->config = $config;
$element_config = array_key_exists('element_conf', $this->config)
? $this->config['element_conf']
: array();
$this->element = new Element($element_config);
}
public function run()
{
$this->element->behave();
// ...
}
// ...
}
class Element
{
protected $type;
protected $config;
protected $default_config = array(
'behaviour_type' => 'evil',
'can_kill_people' => true
);
public function __construct(array $config)
{
$this->config = array_replace($this->default_config, $config);
$this->type = $this->config['behaviour'];
}
public function behave()
{
// ...
}
// ....
}
class Config
{
// get data from config file and makes it available with a static getter/setter
}
-------------------------------
$element_conf = array(
'can_kill_people' => false
);
$process_conf = array(
'default_output_path' => Config::get('default_output_path'),
'element_conf' => $element_conf
);
$pr = new Process($process_conf);
$pr->run();
I would like to keep the encapsulation as high as possible, so I avoided to have a direct reference into the classes to the Config class (the config could arrive from some other place as well).
I would like to receive your thoughts about:
The way is provided the configuration for the inner class (Element). I would like to initialize its config at the top level
(before calling the run()
method); but I don't find nice the way
the configuration for Element is dependant on the code from
Process.
The way to provide configuration for a class. Would it better to pass/set an array config like in my code, or should I pass every setting as a constructor argument, or set it with a setter?
Would you keep the configuration in a protected property, as an array? Or would you assign each relevant setting to a single protected/private property?
(like I did for Element::type
)
What is your usual approach to manage configurations of a class? Would you try to have class also for storing the configration? Would you prefer arrays? Or passing/setting arguments/properties directly? (this last approach, in my mind, is not so easy to maintain). Or even better, does any design pattern exists specifically for this case?
Upvotes: 0
Views: 133
Reputation: 1090
There is no best way to do something globally, there is a best way to do what you want (generic or not) (apply first assertion :D).
The config defaults
A configuration item may be mandatory or not but should always have a default value (so it could be not mandatory). In my mind, there is 2 way to provide a default value:
But, in fact, you could use both using your own rules.
Using these rules, you could provide a default value to the configuration of your Element. But its current configuration could be provide as a sub-config or another source... that Process can use.
The declarative configuration
In your source code, the configuration is declarative, this means when you develop it, you know that configuration exists and must/could/should be provided. So it doesn't matter if you use an object with private element to store your config values/format or a simple constant per config key.
In my framework, all configurations are stored as arrays in a protected member of a Config class. This is due to the fact i need genericity but i don't allow missing values in config files.
OOP allows only OOP
When you use OOP, use it as much as you can, an object is an instance of a class, the class is declared, you know what its contents means. You can not do generic sources if you don't use objects.
Upvotes: 1
Reputation: 1352
If your process class is to be parametrized by Element object than pass an Element object as a parameter and not its parameters as a parameter. This approach also emphasize that Process class depends on Element class which is not immediately visible from Process constructor right now.
As for the array configuration - in my opinion using arrays is easy for writing but makes it hard to actually use the class, how will you know easily what settings your class support? I'd rather use either individual parameters in constructor or separate configuration class with defined properties.
How you do things inside the class itself doesn't really matter that much as long as you wrap it up in some reasonable public interface. What you want to do is keep as much stuff private as possible to keep the ability to change the inner workings of the class if necessary while maintaining backwards compatible public interface. Also keep in mind that protected is pretty much the same as public when it comes to your ability to change it without breaking backwards compatibility as protected properties and methods can be used by child classes.
One last thing - if your class really have many parameters that change its behavior then maybe you should consider whether it wouldn't be better to split these different behaviors to new classes that would extend the base class or implement its interface (whatever suits your situation better).
Upvotes: 1