1. 程式人生 > >模板方法模式 + 觀察者模式 + 簡單工廠模式 + 單例模式實現一個簡單的數據表讀寫

模板方法模式 + 觀察者模式 + 簡單工廠模式 + 單例模式實現一個簡單的數據表讀寫

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

  

模板方法模式 + 觀察者模式 + 簡單工廠模式 + 單例模式實現一個簡單的數據表讀寫