建筑设计帮助 - OOP固体原则

时间:2016-01-31 14:44:40

标签: php oop architecture solid-principles

我正在尝试制作开源缓存库。库的目的是提供将变量(可以是对象,可以是数组,可以是任何东西)存储到文件中然后在调用时检索它的方法。 (通常那些变量值是大量数据库查询和计算的结果)。

该项目的基本目标是实践面向对象的面向设计原则。

如果任何人可以指出我违反了固体原则以及如何解决这个问题

我完全理解stackoverflow不是代码编写服务,但是我正在使这个库开源,所以它会使我们的社区受益。

所以这是我的文件结构。

enter image description here

我是UML的新手,所以如果发现任何错误,请忽略

enter image description here

这是类实现。

缓存     

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 = "Y-m-d") {
        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;
    }

}

用法

$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存储库

https://github.com/FaizRasool/EPC

1 个答案:

答案 0 :(得分:4)

非常好的问题,但整本书可能都写在这上面,这很难回答。

我从这个简单的问题开始:在下面的选择中哪些更好地描述了缓存?

  1. 缓存是一种机制,允许将函数的结果存储到文件中若干天,以便快速访问它。

  2. 缓存是一种机制,只要满足相关的保留策略,就可以保留操作的结果,以便快速访问它。

  3. 没有一个定义是完美的,这不是重点,但我想强调的是#1解释了具有非常具体的基础设施细节的缓存,而#2以更抽象的方式定义了机制。

    希望您现在已经意识到您设计IMO的最大缺陷之一。各种抽象都是错误的:

    1. 存储机制的抽象取决于特定的基础架构细节:整个API围绕文件。如果我想要一个内存缓存怎么办?

    2. 数据保留策略算法非常具体:数据仅保留特定天数。如果我想在几分钟内表达缓存,如果计数器重置,则可以访问数据,该怎么办?

    3. 我给你的一个建议是始终挑战你的抽象,并确保它们不是太具体,以便你的代码可以扩展和重用,但也不能太宽。注意问题领域的语言对此有很大帮助。

      显然有更多可以说的,有时候依赖技术是正确的选择,但我认为我的答案会有所帮助......