模板方法模式 + 觀察者模式 + 簡單工廠模式 + 單例模式實現一個簡單的數據表讀寫
阿新 • • 發佈:2018-04-06
private 數據庫鏈 obs imp 通知 model 數據表 ring pri
實現功能:
對數據表的讀要緩存起來,對數據表的寫需要清除緩存.
數據表根據屬性字段來決定是否緩存
可以更換數據庫鏈接方式,比如可以隨時更換為mysql或mysqli()
當插入數據時給出一個通知或者提示,可以外部配置通知
一.數據操作接口
/** * Interface db */ interface dbInterface { // 此處為簡便起見,只定義讀取所有記錄和寫入記錄 public function all(); public function create(array $attributes); }
二.數據庫實現類(單例模式)
1.mysqli
class DbMySQLi implements dbInterface { private $link; private static $instance; private $table; private function __construct() { $this->link = mysqli_connect(‘localhost‘, ‘root‘, ‘root‘, ‘test‘); } public static function getInstance() { if (is_null(self::$instance)) { self::$instance = new self(); } return self::$instance; } public function setTable($table) { $this->table = $table; } /** * @return array|null */ public function all() { $res = mysqli_query($this->link, "select * from {$this->table}"); $data = []; while ($row = mysqli_fetch_assoc($res)) { $data[] = $row; } return $data; } /** * @param array $attributes * @return bool|mysqli_result */ public function create(array $attributes) { $keys = array_keys($attributes); $values = array_values($attributes); foreach ($keys as $key => $val) { $keys[$key] = "`{$val}`"; } foreach ($values as $key => $val) { $values[$key] = "‘{$val}‘"; } $insertKey = implode(‘,‘, $keys); $insertValue = implode(‘,‘, $values); mysqli_query($this->link, "insert into {$this->table}($insertKey) values({$insertValue})"); return mysqli_insert_id($this->link); } public function closeLink() { if ($this->link) { mysqli_close($this->link); } } }
2.mysql
class DbMySQL implements dbInterface { private $link; private static $instance; private $table; private function __construct() { $this->link = mysql_connect(‘localhost‘, ‘root‘, ‘root‘, ‘test‘); } public static function getInstance() { if (is_null(self::$instance)) { self::$instance = new self(); } return self::$instance; } public function setTable($table) { $this->table = $table; } /** * @return array|null */ public function all() { $res = mysql_query("select * from {$this->table}", $this->link); $data = []; while ($row = mysql_fetch_assoc($res)) { $data[] = $row; } return $data; } /** * @param array $attributes * @return bool|mysqli_result */ public function create(array $attributes) { $keys = array_keys($attributes); $values = array_values($attributes); foreach ($keys as $key => $val) { $keys[$key] = "`{$val}`"; } foreach ($values as $key => $val) { $values[$key] = "‘{$val}‘"; } $insertKey = implode(‘,‘, $keys); $insertValue = implode(‘,‘, $values); mysql_query("insert into {$this->table}($insertKey) values({$insertValue})", $this->link); return mysql_insert_id($this->link); } public function closeLink() { if ($this->link) { mysql_close($this->link); } } }
三.配置類
class Config { const DB_TYPE = ‘mysql‘; }
四.cache接口
interface Cache { public function clearCache(); public function setCache($data); public function getCache(); public function getKey(); }
文件緩存實現,此處用trait實現:
trait FileCacheTrait { public function clearCache() { @unlink($_SERVER[‘DOCUMENT_ROOT‘] . ‘/cache-‘ . $this->getKey() . ‘.php‘); } public function setCache($data) { $file = $_SERVER[‘DOCUMENT_ROOT‘] . ‘/cache-‘ . $this->getKey() . ‘.php‘; $cache = ‘<?php‘ . "\n"; $cache .= ‘return ‘; $cache .= var_export($data, true); $cache .= ‘;‘; file_put_contents($file, $cache); } public function getCache() { $file = $_SERVER[‘DOCUMENT_ROOT‘] . ‘/cache-‘ . $this->getKey() . ‘.php‘; if (is_file($file)) { return require $file; } return false; } public function getKey() { return md5($_SERVER[‘PHP_SELF‘] . ‘?‘ . $_SERVER[‘QUERY_STRING‘]); } }
五.通知(觀察者)
接口:
interface ObserverInterface { public function fire(Model $model); }
實現:
class Observer implements ObserverInterface { public function fire(Model $model) { $model = $model->model(); echo "創建{$model->name}, id:{$model->id}"; } }
六.Model虛擬類:通用數據操作
abstract class Model { protected $observers = []; //被觀察者數組 protected $db; protected $model; protected $cache = false; public function __construct() { // 簡單工廠模式 if (Config::DB_TYPE == ‘mysql‘) { $this->db = DbMySQLi::getInstance($this->table()); } else { $this->db = DbMySQL::getInstance($this->table()); } $this->db->setTable($this->table()); } public function all() { if ($this->cache && $cache = $this->getCache()) { return $cache; } $data = $this->db->all(); if ($this->cache) { $this->setCache($data); } return $data; } public function create(array $attributes) { $insertId = $this->db->create($attributes); // 清除緩存 if ($this->cache) { $this->clearCache(); } $this->fill(array_merge($attributes, [‘id‘ => $insertId])); // 如果有設置created被觀察者,直接調用 if (isset($this->observers[‘created‘])) { $this->observers[‘created‘]->fire($this); } return $insertId; } public function __destruct() { $this->db->closeLink(); } public function addObserver($key, ObserverInterface $observer) { $this->observers[$key] = $observer; } public function fill(array $attributes) { $this->model = (object) $attributes; } public function model() { return $this->model; } abstract public function table(); }
七.model實現類
class User extends Model implements Cache { // 配置緩存可用 protected $cache = true; use FileCacheTrait; public function table() { return ‘user‘; } }
八.App類:從外部負責給model綁定被觀察者
class App { public static function observer(Model $model) { $model->addObserver(‘created‘, new Observer($model)); } }
調用:
$user = new User(); App::observer($user); $user->create([‘name‘ => ‘test‘]);
附加:
如果要用閉包調用,則Model類對應部分改為:
// 如果有設置created被觀察者,直接調用 if (isset($this->observers[‘created‘])) { if ($this->observers[‘created‘] instanceof Closure) { call_user_func($this->observers[‘created‘], $this); } else { $this->observers[‘created‘]->fire($this); } }
App改為:
class App { public static function observer(Model $model) { $model->addObserver(‘created‘, function () use($model) { echo "創建{$model->model()->name}, id:{$model->model()->id}"; }); } }
模板方法模式 + 觀察者模式 + 簡單工廠模式 + 單例模式實現一個簡單的數據表讀寫