【问题标题】:Architecture Design Help - OOP Solid Principle架构设计帮助 - OOP Solid Principle
【发布时间】:2016-05-08 23:49:32
【问题描述】:

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

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

如果有人能指出我在哪里违反了坚实的原则以及如何解决它

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

这是我的文件结构。

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

这是类的实现。

缓存

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);
        }
    }

}

文件处理程序

<?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));
    }

}

缓存配置器

<?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);
    }
}

婴儿车格式化程序

<?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

【问题讨论】:

  • 您好,如果您将项目发布在 github 上,审核会更容易。
  • @JorelC gotcha,很快就会发布链接。
  • 你忘了这个问题吗?
  • @JorelC 这里是链接:github.com/FaizRasool/EPC

标签: php oop architecture solid-principles


【解决方案1】:

非常好的问题,但可能会写一整本书,这很难回答。

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

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

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

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

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

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

  2. 数据保留策略算法非常具体:数据将仅保留特定天数。如果我想在几分钟内表达缓存,每次访问数据时计数器都会重置?

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

显然可以说的远不止这些,有时依赖技术是正确的选择,但我认为我的回答会有所帮助......

【讨论】:

  • 对可靠原则的可靠回答:) - 我感谢您对设计的关注,它们都是非常有效的观点。现在我回到白板。感谢您的帮助。
  • @FaizRasool 太好了,如果您需要更多指导,请告诉我,如果答案符合您的期望,请不要忘记接受;)
  • @FaizRasool 我会说它更好,但是如果不同的缓存机制需要稍微不同的配置怎么办?例如,SQL 中的缓存可能需要一个连接字符串,但文件系统需要一个目录。你不喜欢多态配置吗?例如。 FileSystemCacheConfig extends CacheConfig?
  • @FaizRasool 你有很多 setIntervalXXX 方法,最好合并到一个 setInterval(Interval interval) 方法中,其中Interval 是一个代表区间的值对象类。然后你可以有类似config.setInterval(Interval.ofMinutes(10).plusSeconds(5))的东西。
  • 如果你查找 CacheFactory 类,它有 createFileCache 的静态方法。通常创建它是为了处理不同类型的缓存。如果在不久的将来,如果有人有数据库缓存,它将有不同的工厂方法。
猜你喜欢
  • 2011-01-11
  • 1970-01-01
  • 2011-03-07
  • 1970-01-01
  • 2010-11-21
  • 2016-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多