I have a dilemma in designing classes. I am working hard to respect the principles of SOLID, but I don’t know how to handle dependency injections.
Here is my dilemma:
- I read that it is bad practice to create objects inside classes in order to avoid dependency injection. So where should our dependencies be created in a full object application? In a special object that is only responsible for dependency instances? If so, what is the name of this object and how to define it? Is this what we call a “controller”?
- This "controller", what is the correct way to unit test it? Should we unit test this?
- In a full POO application, how to avoid passing our objects (often the same) between classes? For example, a database object, a log, ... Thus, we run the risk of having constructors with many parameters, right?
To illustrate my dilemma, I tried to set a precedent.
I want to create a script (which I partially executed below) that generates a file and prints another one:
<?php
class Script
public function run() {
$fileComputor = new FileComputer(...);
$file = $fileComputor->compute();
$db = new Db(new PdoAdapter());
$printerDriver = new Driver(new HttpRequest(new CurlAdapter()));
$log = new Log($db);
$queue = new Queue($db);
$statsUpdater = new StatsUpdater($db);
$monitor = new Monitor(new StatsdDriver(new SocketAdapter()));
$queueModel->push($file);
$printer = new Printer($printerDriver, $log, $queue, $monitor, $statsUpdater);
$printer->print();
}
}
class Printer {
protected $_driver;
protected $_log;
protected $_queue;
protected $_monitor;
protected $_statsUpdater;
public function __construct($driver, $log, $queue, $monitor, $statsUpdater) {
$this->_driver = $driver;
$this->_log = $log;
$this->_queue = $queue;
$this->_monitor = $monitor
$this->_statsUpdater = $statsUpdater;
}
public function print() {
if ($this->_queue->hasNext()) {
$file = $this->_queue->getNext();
$this->_driver->print($file);
$this->_log->log('File has been printed');
$this->_monitor->sendCount(1);
$this->_statsUpdater->increment();
}
}
}
?>
What do you think of this implementation?
Each function that we want to connect to our Printer class will cause a new dependency to be passed to the constructor (if, for example, we want to generate syslog to measure the time it takes to process the printer, etc.).
In the near future, we will have 10 to 15 parameters in the constructor call.
source
share