Architecture Design Reference - OOP Hardness Principle

I am trying to create an open source Cache library. The purpose of the library is to provide a way to store a variable (may be an object, may be an array, may be any) for files, and then restore it back by call. (usually this variable is the result of mass queries and database calculations).

The main goal of the project is to apply the principle of object-oriented design called Solid.

If someone can indicate where I am breaking a solid principle and how to fix it

I fully understand that stackoverflow is not a code writing service, but I am making this library open source, so it will benefit our community.

So here is my file structure.

enter image description here

I am new to UML, so please ignore if errors are detected

enter image description here

here is the implementation of the classes.

Cache

namespace library\pingle\cache; use library\pingle\cache\config\CacheConfigurator; use library\pingle\cache\file\FileHandler; /** * @property CacheReader $cache_reader * @property CacheWriter $cache_write */ Class Cache { private $config; private $file_hander; private $cache_reader; private $cache_write; private $cache_directory; private $cache_kept_days; private $cache_file_prams; private $function_name; private $file_path; function __construct(CacheConfigurator $config) { $this->file_hander = new FileHandler(); $this->config = $config; list($this->cache_directory, $this->function_name, $this->cache_kept_days, $this->cache_file_prams) = $this->config->getConfig(); $this->file_path = $this->generateFileName($this->cache_file_prams); } public function read() { if (is_null($this->cache_reader)) { $this->cache_reader = new CacheReader($this->file_hander); } return $this->cache_reader->readCache($this->file_path); } public function write($data) { if (is_null($this->cache_write)) { $this->cache_write = new CacheWriter($this->file_hander); } if (!$this->file_hander->checkDirectory($this->cache_directory . "/" . $this->function_name)) { $this->file_hander->createDirectory($this->cache_directory . "/" . $this->function_name); } $this->cache_write->writeCache($this->file_path, $data); } public function check() { if ($this->file_hander->checkFileExits($this->file_path)) { if (time() - filemtime($this->file_path) >= 60 * 60 * 24 * $this->cache_kept_days) { return false; } return true; } else { return false; } } private function generateFileName(Array $nameprams) { $this->file_name = ""; $file = "CC"; foreach ($nameprams as $key => $value) { $file .= "-$key|$value-"; } $file .= ".bak"; return $this->cache_directory . "/" . $this->function_name . "/" . $file; } } 

AbstractCache

 <?php namespace library\pingle\cache; use library\pingle\cache\file\FileHandler; abstract Class AbstractCache { protected $file_handler; public function __construct(FileHandler $file_handler) { $this->file_handler = $file_handler; } protected function checkDirectory($path) { //check directory exists $dircheck = $this->file_handler->checkDirectory(dirname($path)); if ($dircheck) { //check directory permission if ($this->file_handler->checkPermission(dirname($path))) { return true; } else { throw new \Exception("Directory ($path) Permission Error."); } } else { throw new \Exception("Directory ($path) not found."); } } } 

Cachereader

 <?php namespace library\pingle\cache; use library\pingle\cache\file\FileHandler; /** * @property FileHandler $file_handler */ Class CacheReader extends AbstractCache { public function __construct(FileHandler $file_handler) { parent::__construct($file_handler); } public function readCache($path) { if ($this->checkDirectory($path)) { //delete the file if it exits if ($this->file_handler->checkFileExits($path)) { return $this->file_handler->readFile($path); } else { throw new \Exception("File ($path) not found"); } } } } 

Cachewriter

 <?php namespace library\pingle\cache; use library\pingle\cache\file\FileHandler; /** * @property FileHandler $file_handler */ Class CacheWriter extends AbstractCache { public function __construct(FileHandler $file_handler) { parent::__construct($file_handler); } function writeCache($path, $data) { if ($this->checkDirectory($path)) { //delete the file if it exits if ($this->file_handler->checkFileExits($path)) { $this->file_handler->deleteFile($path); } //write cache $this->file_handler->writeFile($path, $data); } } } 

Filehandler

 <?php namespace library\pingle\cache\file; Class FileHandler { public function writeFile($path, $data) { $content = serialize($data); file_put_contents($path, $content); } public function createDirectory($path) { mkdir($path); } public function deleteFile($path) { unlink($path); } public function checkDirectory($path) { if (file_exists($path)) { return true; } else { return false; } } public function checkPermission($path) { if (is_writable($path)) { return true; } else { return false; } } public function checkFileExits($path) { if (is_file($path)) { return true; } return false; } public function readFile($path) { return unserialize(file_get_contents($path)); } public function checkFileCreated($path, $format = "Ymd") { return date($format, filemtime($path)); } } 

CacheConfigurator

 <?php namespace library\pingle\cache\config; /** * @property PramsFormatter $prams_formatter */ class CacheConfigurator { private $prams_formatter; private $cache_directory; private $cache_kept_days; private $cache_file_prams; private $function_name; function __construct($file_prams) { $this->cache_file_prams = $file_prams; $this->cache_directory = ""; //Def Path } public function setCacheDirectory($cache_directory) { $this->cache_directory = $cache_directory; return $this; } public function setFunction($function) { $this->function_name = $function; return $this; } public function setCacheKeptDays($cache_kept_days) { $this->cache_kept_days = $cache_kept_days; return $this; } public function getConfig() { $this->prams_formatter = new PramsFormatter($this->cache_file_prams); $this->cache_file_prams = $this->prams_formatter->getFormattedPrams(); $this->function_name = $this->prams_formatter->cleanValue($this->function_name); return array($this->cache_directory, $this->function_name, $this->cache_kept_days, $this->cache_file_prams); } } 

Pramsformatter

 <?php namespace library\pingle\cache\config; class PramsFormatter { private $cache_file_prams; public function __construct(Array $prams) { $this->cache_file_prams = $prams; $this->formatPrams(); } public function formatPrams() { if (is_array($this->cache_file_prams)) { foreach ($this->cache_file_prams as $k => $value) { $this->cache_file_prams[$k] = $this->cleanValue($value); } } } public function cleanValue($value) { if (is_array($value)) { throw new \Exception("Array as paramter value is not accepted"); } else { return str_replace(array(" ", " ", ".", "/", "\\"), "-", $value); } } public function getFormattedPrams() { return $this->cache_file_prams; } } 

Using

 $cache_config = new CacheConfigurator(array('carrier_id' => $invoicedata['carrier_id'], 'month' => $month, 'year' => $year)); $cache_config->setFunction('Inter-department Calls'); $cache_config->setCacheKeptDays(30); $cache_config->setCacheDirectory("bin/cache"); $cache = new Cache($cache_config); if ($cache->check()) { $node = $cache->read(); } else { //calculate node $cache->write($node); } 

Git Advanced Design Repository

https://github.com/FaizRasool/EPC

+5
source share
1 answer

A very good question, but a whole book could probably be written on this book, which makes it quite difficult to answer.

I would start with this simple question: what better describes caching in the options below?

  • Caching is a mechanism that allows you to store the result of a function in a file for several days to provide quick access to it.

  • Caching is a mechanism that allows you to save the result of an operation until the corresponding storage policy is satisfied in order to provide quick access to it.

None of the definitions are perfect, and this is not so, but I would like to emphasize that # 1 explains caching with very specific infrastructure details, and # 2 defines the mechanism in a more abstract way.

I hope you now understand one of the biggest flaws in your IMO design. Various abstractions are wrong:

  • The abstraction of the storage engine depends on a specific infrastructure detail: the entire API revolves around files. What if I need a cache in memory?

  • The algorithm of the data storage policy is very specific: data will be stored only for a certain number of days. What if I would like to express the cache in minutes, where the counter resets the evertime the data is accessing?

One tip I would give you is to always challenge your abstractions and make sure they are not too specific so your code can be extensible and reusable, but not too wide. Pay attention to the language of the problem area, which helps a lot in this.

Obviously, much more than this could be said, and sometimes technology-dependent, is the right choice, but I think my answer will help ...

+4
source

Source: https://habr.com/ru/post/1241933/


All Articles