模板方法模式 + 观察者模式 + 简单工厂模式 + 单例模式实现一个简单的数据表读写

Posted 罗夏

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板方法模式 + 观察者模式 + 简单工厂模式 + 单例模式实现一个简单的数据表读写相关的知识,希望对你有一定的参考价值。

实现功能:

对数据表的读要缓存起来,对数据表的写需要清除缓存.

数据表根据属性字段来决定是否缓存

可以更换数据库链接方式,比如可以随时更换为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}";
        });
    }
}

  

 

以上是关于模板方法模式 + 观察者模式 + 简单工厂模式 + 单例模式实现一个简单的数据表读写的主要内容,如果未能解决你的问题,请参考以下文章

c#面向对象10--简单工厂设计模式

24种设计模式的简单理解

设计模式目录

二十三种设计模式

设计模式总结

C#设计模式汇总