Друзья, нужен ваш совет. Имеются 3 класса для логирования сообщений(в файл, в базу данных и stdout). Нужно каким то образом применить наследование к этим классам. Проглядываются общие черты, но объеденить это всё не удаётся. Надеюсь на вашу помощь PHP: class LogFile { protected $path_to_file; private function __construct($path_to_file) { $this->path_to_file = $path_to_file; } private function getDate() { return '[' . date("Y-m-d H:i:s") . ']'; } public function addLog($message) { if(gettype($message) == 'string'){ file_put_contents($this->path_to_file, self::getDate() .' '. $message . "\r\n", FILE_APPEND); } else if(gettype($message) == 'array'){ foreach ($message as $log){ file_put_contents($this->path_to_file, self::getDate() .' '. $log . "\r\n", FILE_APPEND); } } else if(gettype($message) == 'object'){ foreach ($message as $prop => $value){ file_put_contents($this->path_to_file, self::getDate() .' '. $prop. ' => '. $value . "\r\n", FILE_APPEND); } } } public function changePath($path){ $this->path_to_file = $path; } } class LogDB { protected $host; protected $dbname; protected $tbname; protected $login; protected $password; private function __construct($host, $dbname, $tbname, $login, $password) { $this->host = $host; $this->dbname = $dbname; $this->tbname = $tbname; $this->login = $login; $this->password = $password; } private function getDate() { return '[' . date("Y-m-d H:i:s") . ']'; } public function addLog($message) { $db = new PDO("mysql:host=$this->host; dbname=$this->dbName","$this->login", "$this->password"); if(gettype($message) == 'string') { $db->query("INSERT INTO $this->tbName(date, message) VALUES('".self::getDate()."', '$message')"); } else if(gettype($message) == 'array') { foreach ($message as $item){ $db->query("INSERT INTO $this->tbName(date, message) VALUES('".self::getDate()."', '$item')"); } } else if(gettype($message) == 'object'){ foreach ($message as $item => $value){ $db->query("INSERT INTO $this->tbName(date, message) VALUES('".self::getDate()."', '$item : $value')"); } } $db = null; } public function changeConfig($host, $dbname, $tbname, $login, $password) { $this->host = $host; $this->dbname = $dbname; $this->tbname = $tbname; $this->login = $login; $this->password = $password; } } class LogSteam { private function getDate(){ return '[' . date("Y-m-d H:i:s") . ']'; } public function addLog($message) { $std = fopen('php://stdout', "a+"); if(gettype($message) == 'string'){ fwrite($std, self::getDate() . " " . $message . "\r\n"); } else if(gettype($message) == 'array'){ foreach ($message as $item){ fwrite($std, self::getDate() . " " . $item . "\r\n"); } } else if(gettype($message) == 'object'){ foreach ($message as $item => $value){ fwrite($std, self::geDate() . " " . $item . " : " . $value . "\r\n"); } } fclose($std); } }
Понимаете, это тестовое задание меня попросил сделать работодатель. В первом варианте я сделал абстрактный класс, дабы просто применить наследование (в задании сказано использовать объектно-ориентированный подход, я подумал что нужно использовать все его возможности ). Но меня попросили переделать с формулировкой "разобраться в наследовании". Лично мне кажется что в данном примере наследование не стоит применять, дабы не нагружать и без того простую систему. Но раз работодатель попросил, нужно выполнять)
Ну так элементарно. Они все логируют, у всех есть абсолютно одинаковый метод getDate(), и у всех есть addMessage(), реализация которого меняется в зависимости от типа логирования. Получается достаточно простая картинка: При этом у класса Loger getDate() - protected-метод, который используют наследники. A addMessage() - абстрактный, поэтому Logger (на картинке опечатка в названии, но не суть) - абстрактный класс. Делается для того, чтобы путём смены одной строки кода можно было выбирать, куда писать логи - в базу или в файл.
Именно это я и делал в первой реализации) PHP: abstract class Loger { abstract protected function getDate(); abstract public function addLog($message); } Может быть в данном контексте разумнее было использовать интерфейс?
А зачем getDate() абстрактная? Она же одинаково реализована во всех классах. Думаю, к этому и придрались. У меня на UML она не повторяется больше нигде
Ну а какой смысл повторять код getDate() во всех трёх классах? А ещё можно чуть-чуть модифицировать LogFile, и тогда от него можно будет унаследовать LogSteam: PHP: class LogFile extends Loger { protected $path_to_file; public function __construct($path_to_file) { $this->path_to_file = $path_to_file; } public function addLog($message) { $std = fopen($this->path_to_file, "a+"); if(gettype($message) == 'string'){ fwrite($std, self::getDate() . " " . $message . "\r\n"); } else if(gettype($message) == 'array'){ foreach ($message as $item){ fwrite($std, self::getDate() . " " . $item . "\r\n"); } } else if(gettype($message) == 'object'){ foreach ($message as $item => $value){ fwrite($std, self::geDate() . " " . $item . " : " . $value . "\r\n"); } } fclose($std); } public function changePath($path){ $this->path_to_file = $path; } } class LogSteam extends LogFile { public function __constuct() { parent::__constuct("php://stdin"); } public function changePath($path){ throw new Exception(); } }
Ещё одна идея, кстати: PHP: class Logger { protected function getDate() { return '[' . date("Y-m-d H:i:s") . ']'; } abstract protected function writeMsg($msg); final public function addLog($msg) { if(gettype($message) == 'string'){ $this->writeMsg($message) } else if(gettype($message) == 'array'){ foreach ($message as $item){ $this->writeMsg(self::getDate() . " " . $item . "\r\n"); } } else if(gettype($message) == 'object'){ foreach ($message as $item => $value){ $this->writeMsg(self::geDate() . " " . $item . " : " . $value . "\r\n"); } } } } Дальше сделаете? Опять же, чтоб ваши повторы кода сократить в разных классах.