PHP设计模式之:数据映射模式教程

 更新时间:2016年11月25日 14:56  点击:2158
php中的设计模式中有很多的各种模式了,在这里我们来为各位介绍一个不常用的数据映射模式吧,希望文章能够帮助到各位。


之前的几种设计模式,都是大大提高了PHP代码的可读性、可维护性。但是,在WEB应用中还有更重要的需求与挑战,那就是:数据库应用。可之前的设计模式,都没有涉及于此。今天写到的,数据映射模式就是能够更好的组织应用程序与数据库进行交互。
博主这两天也是花了点时间对,这种模式有了那么一点的了解。斗胆在这个里献丑,按照自己的理解,写一点东西与大家分享,互相学习。
当然说到数据映射模式,就不得不提到对象关系映射(Object Relational Mapping,简称ORM),用于实现面向对象编程语言里不同类型系统的数据之间的转换。一般ORM框架对付简单的应用系统来说都能满足基本需求,可以大大降低开发难度,提高开发效率,但是它在SQL优化方面,肯定是比纯SQL语言要差很多,对复杂关联、SQL内嵌表达式的处理都不是很理想。
对于博主目前使用的TP框架,其核心文件Model.class.php就是实现了ORM和ActiveRecords模式,在项目中所有的模型也都是继承这个模型类。
好吧,还是不丢人说这些废话了,自己参考编写整理了一份实例,给大家分享一下,互相交流。

首先我们需要一个数据库中间层实现类,使用pdo进行数据库访问。当然这个类不是今天的重点,我也是从网上拷来的,可以直接忽略。

创建一个DB类文件 Db.class.php

<?php
/*
 * 数据库中间层实现类
 */
class Db { 
    public static $db = null; 
    private $_dbh = null; 
    public static function getInstance() { 
        if( self::$db == null ){ 
            self::$db = new self(BACKEND_DBHOST ,BACKEND_DBUSER ,BACKEND_DBPW ,BACKEND_DBNAME); 
        } 
        return self::$db; 
    }
 
    private function __construct( $host ,$user ,$pass ,$dbname ){ 
        try { 
            $this->_dbh = new PDO('mysql:dbname='.$dbname.';host='.$host,$user,$pass); 
            $this->_dbh->query('SET NAMES '. BACKEND_DBCHARSET); 
            $this->_dbh->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true); 
            $this->_dbh->setAttribute(PDO::ATTR_ERRMODE, true); 
        } catch (PDOException $e) { 
            throw new Exception('Can not connect db'); 
        } 
    }
    public function getOne($sql){ 
        try { 
            $rs = $this->_dbh->query($sql); 
            $result = $rs->fetch(PDO::FETCH_ASSOC); 
            if(!empty($result)) { 
                return $result; 
            } 
        } catch (PDOException $e) { 
            throw new Exception($this->_dbh->errorInfo()); 
        } 
        return false; 
    } 
 
    public function getAll($sql){ 
        try { 
            $rs = $this->_dbh->query($sql); 
            $result = $rs->fetchAll(PDO::FETCH_ASSOC); 
            if(!empty($result)) { 
                return $result; 
            } 
        } catch (PDOException $e) { 
            throw new Exception($this->_dbh->errorInfo()); 
        } 
        return false; 
    } 
 
    public function exec($sql){ 
        try { 
            $exec = $this->_dbh->exec($sql); 
        } catch (PDOException $e){ 
            throw new Exception($this->_dbh->errorInfo()); 
        } 
        return $exec;
    }
 
    public function getLastId() 
    { 
        return $this->_dbh->lastInsertId(); 
    } 
} 
?>

数据映射类 Table.class.php

<?php
/** 
 * 数据映射类
 * 部分代码来源TP框架
 * 使用相关魔术方法 则映射的表修改字段后无需修改属性值
 */ 
class Table{
 
    // 数据信息
    protected $data = array();
 
    // 数据信息
    protected $db = null;
 
    // 表信息
    protected $tableName = '';
    public function __construct() {
        $this->db = Db::getInstance();
    }
 
    /**
     * 设置数据对象的值
     */
    public function __set($name,$value) {
        // 设置数据对象属性
        $this->data[$name] = $value;
    }
    /**
     * 获取数据对象的值
     */
    public function __get($name) {
        return isset($this->data[$name])?$this->data[$name]:null;
    }
 
    /*
     * 添加
     * 修改、删除也和添加类似,就不一一列举了
     */
    public function add() {
        $data = $this->data;
        foreach($data as $k=>$v) {
            $fieldArr[] = $k;
            $valueArr[] = "'".$v."'";
        }
        $fields = implode(',', $fieldArr);
        $values = implode(',', $valueArr);
        $sql = 'INSERT INTO '.$this->tableName.' ('.$fields.') VALUES ('.$values.')';
        $result = $this->db->exec($sql);
        if($result) {
            return $this->db->getLastId();
        } else {
            return false;
        }
    }
}
?>

表对应的类文件 UserTable.class.php

<?php
/** 
 * 数据映射到表 
 * 一般根据表的结构由工具自动生成,比如Yii框架等。
 */
class UserTable extends Table { 
    protected $tableName = 'user';
}
?>
 
使用方式 index.php
<?php
/** 
 * 数据库配置文件 
 */ 
define('BACKEND_DBHOST', 'localhost'); 
define('BACKEND_DBUSER', 'root'); 
define('BACKEND_DBPW', ''); 
define('BACKEND_DBNAME', 'test'); 
define('BACKEND_DBCHARSET', 'utf-8');
/*
 * 这里实例化对象时可以使用之前介绍的工厂模式和注册模式,来实例化和管理实例化对象
 * TP框架中的D方法就是做了这部分工作
 */
$UserTable = new UserTable();
$UserTable->username = 'Anrai';
$UserTable->mobile = '123456789';
$UserTable->email = 'huanglei.web@gmail.com';
echo $UserTable->add();
/*
数据表sql
CREATE TABLE `user` (
 `uid` int(11) NOT NULL AUTO_INCREMENT,
 `username` varchar(30) NOT NULL,
 `mobile` varchar(11) NOT NULL DEFAULT '0',
 `email` varchar(60) NOT NULL DEFAULT '0',
 PRIMARY KEY (`uid`),
 KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
*/
?>

适配器模式是php设计模式中的一个常用的模式了,很多朋友对于这个适配器模式不了解,下面小编和各位介绍一下吧,希望对大家帮助

适配器模式有什么用?

 

将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原来由于接口不兼容而不能一起工作的那此类可以一起工作

适用性

1、你想使用一个已经存在的类,而它的接口不符合你的需求
2、你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类协同工作
3、你想使用一个已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口(仅限于对象适配器)

应用举例,例如PHP的数据库操作有MySQL、Mssql、PDO等,可以用适配器模式统一成一致。类似的场景还有cache适配器,将memcache、redis、file、apc等不同的缓存函数,统一成一致。

接下来我们以数据库操作来举例,为了编辑方便,博主就把代码都写一起了

<?php
/** 
 * PHP设计模式之适配器模式实例
 *
 */
  
/**
 * 目标角色
 * 创建一个接口文件 DataBase.php
 * 定义一个数据库接口
 * 声明方法
 */
interface IDataBase {
    public function connect($host, $user, $passwd, $dbname);
    public function query($sql);
    public function close();
}
/**
 * 源角色
 */
class Adaptee {
 
    /**
     * 源类含有的方法
     */
    public function connect($host, $user, $passwd, $dbname) {
        return 'Adaptee';
    }
}
  
/**
 * 类适配器角色
 * 创建mysql操作类文件 Mysql.php
 * 继承接口 实现接口方法
 */
class Mysql implements IDataBase {
    private $_adaptee; 
    function __construct() {  
        $this->_adaptee = new Adaptee();   
    }
    public function connect($host, $user, $passwd, $dbname){
        /**
         * code...
         * 委派调用Adaptee的connect方法
         */
        $this->_adaptee->connect($host, $user, $passwd, $dbname);
        //return 'ok';
    }
    public function query($sql){
        /**
         * code...
         */
        return 'ok';
    }
    public function close(){
        /**
         * code...
         */
        return 'ok';
    }
}
  
/**
 * 类适配器角色
 * 创建mssql操作类文件 Mssql.php
 * 继承接口 实现接口方法
 */
class Mssql implements IDataBase {
    public function connect($host, $user, $passwd, $dbname){  
        /**
         * code...
         */
        return 'ok';
    }
    public function query($sql){
        /**
         * code...
         */
        return 'ok';
    }
    public function close(){
        /**
         * code...
         */
        return 'ok';
    }
}
/**
 * 类适配器角色
 * 创建pdo操作类文件 Pdo.php
 * 继承接口 实现接口方法
 */
class Pdfo implements IDataBase {
    public function connect($host, $user, $passwd, $dbname){  
        /**
         * code...
         */
        return 'ok';
    }
    public function query($sql){
        /**
         * code...
         */
        return 'ok';
    }
    public function close(){
        /**
         * code...
         */
        return 'ok';
    }
}
/**
 * 使用
 * 这样就可以任意的在三种适配器之间进行切换
 */
$db = new Mysql();
echo $db->connect('127.0.0.1', 'root', 'root', 'test');
echo $db->query('show databases');
echo $db->close();
?>

博主也参考了网上一些示例,总觉得写的也不明确,直到写完这篇,博主依旧疑惑。不知道我的理解是否正确,看过之后的朋友还望指点一二。

好了,今儿就到这,更多深入信息可以自己去网上找,或者查看相关书籍

设计模式中的观察者模式我相信很多php开发者都不是很了解了,下面一聚教程小编来为各位整理了一篇相关的文章供各位参考。


一些面向对象的编程方式,提供了一种构建对象间复杂网络互连的能力。当对象们连接在一起时,它们就可以相互提供服务和信息。这个模式对于大型系统项目来说应该是挺挺有用的,通俗的讲,这种模式允许某个类去观察另一个类。当一个类被改变时,观察类就会收到通知并且做出相应的动作。

在平时的项目中还是挺有用的,比如一个用户下了一笔订单,下单成功后,就需要去发送短信/邮件的通知,库存的修改,账户余额的修改等等很多操作。

在之后的PHP5.0起,内置的SPL标准库中就提供了这种设计模式接口供大家使用,接下了就通过实例来学习一下。

SPL 提供了 SplSubject 和 SplObserver 接口。
SplSubject 接口提供了attach()、detach()、notify() 三个方法。而 SplObserver 接口则提供了 update()方法。

<?php

/** 

 * 这一模式的概念是SplSubject类维护了一个特定状态,当这个状态发生变化时,它就会调用notify()方法。 

 * 调用notify()方法时,所有之前使用attach()方法注册的SplObserver实例的update方法都会被调用。 

 * 

 */ 

interface SplSubject{ 

    public function attach(SplObserver $observer);//注册观察者 

    public function detach(SplObserver $observer);//释放观察者 

    public function notify();//通知所有注册的观察者 

} 

interface SplObserver{ 

    public function update(SplSubject $subject);//观察者进行更新状态 

}

?>

 

使用所提供的接口,来实现观察者模式

<?php
/** 
 *具体目标
 */ 
class Salary implements SplSubject { 
    private $observers, $money; 
    public function __construct() { 
        $this->observers = array(); 
    } 
 
    public function attach(SplObserver $observer) { //注册观察者 
        $this->observers[] = $observer; 
    } 
 
    public function detach(SplObserver $observer) { //释放观察者 
        if($idx = array_search($observer,$this->observers,true)) { 
            unset($this->observers[$idx]); 
        } 
    } 
 
    public function notify() { //通知所有观察者 
        foreach($this->observers as $observer) { 
            $observer->update($this); 
        } 
    }
    public function payoff($money) { //发工资方法
        $this->money = $money; 
        $this->notify(); //通知观察者
    }
} 
/** 
 * 具体观察者
 */ 
class Programmer1 implements SplObserver { 
    public function update(SplSubject $subject) { 
        echo 'Programmer1 发工资了!<br/>'; 
    } 
}
class Programmer2 implements SplObserver { 
    public function update(SplSubject $subject) { 
        echo 'Programmer2 也发工资了!<br/>'; 
    }
} 
 
$subject = new Salary(); 
$observer1 = new Programmer1();
$observer2 = new Programmer2();
//注册观察者
$subject->attach($observer1);
$subject->attach($observer2);
//发工资操作,发起通知
$subject->payoff('20K');
?>

通过Observer模式,把一对多对象之间的通知依赖关系的变得更为松散,大大地提高了程序的可维护性和可扩展性,也很好的符合了开放-封闭原则。东西是不错,如何能够更好的去使用它,仍需要多加实践、联系。

原型模式和其它的模式相对有一些不同之处了,这个也是当然了所有的设计模式中的各种模式都有自己的特色了,下面一起来看看。


原型模式其实和工厂模式比较类似,都是用来创建对象的,只不过与工厂模式的实现不同。原型模式是先创建好一个原型对象,然后通过clone原型对象来创建新的对象。这样就免去了类创建时重复的初始化操作了。原型模式适用于大对象的创建,因为在创建一个大对象时,需要很大的开销。如果每次都去new就会消耗很大,原型模式仅需从内存拷贝既可。

还是继续通过实例来向大家演示一下

<?php
/**
 * 抽象原型角色
 */
interface Prototype {
    public function clone_obj();
}
/**
 * 具体原型角色
 */
class Concrete implements Prototype{
 
    private $data;
 
    public function __construct($data) {
        $this->data = $data;
    }
    public function get_data() {
        return $this->data;
    }
 
    public function clone_obj() {
        /*
         * 深拷贝实现
         */
        /*$serialize_obj = serialize($this); // 序列化
        $clone_obj = unserialize($serialize_obj); // 反序列化 
        return $clone_obj;*/
 
        return clone $this; // 浅拷贝
    }
}
/**
 * 测试深拷贝用的引用类
 */
class Demo {
    public $arr;
}
$demo = new Demo();
$demo->arr = array(1, 2);
$concrete = new Concrete($demo);
$object1 = $concrete->clone_obj();
var_dump($concrete->get_data());
echo '<br />';
var_dump($object1->get_data());
echo '<br />';
//测试深拷贝
$demo->arr = array(3, 4);
var_dump($concrete->get_data());
echo '<br />';
var_dump($object1->get_data());
echo '<br />';
?>

更多的详细说明和实例

php面向对象的设计模式中有很多种模式了,今天我们为各位介绍的是装饰器模式的一个学习笔记了,有需要了解php装饰器模式的朋友可以和小编来看看。


我们在使用面向对象的日常开发过程中,或许会碰见需要对某个方法或者某个对象,添加新的行为。然而常见的做法是,写一个子类继承需要改写的类,然后去重新实现类的方法。

但是装饰器模式(Decorator),可以动态地添加修改类的功能,在使用装饰器模式,仅需在运行时添加一个装饰器对象既可实现,相对与生成子类更加的灵活。

在我们需要改写一个类的时候通常的做法是采用继承的方式来重新方法,如下代码

/*
 * 比如我们需要改写一串字符串的样式,采用继承的写法。
 */
class Canvas {
    function draw($width = 20, $height = 10) {
        for($i = 0; $i < $height; $i++) {
            for($j = 0; $j < $width; $j++) {
                echo '*';
            }
            echo '<br/>';
         }
     }
}
class Canvas2 extends Canvas {
    function draw($width = 20, $height = 10) {
        echo "<div style='color: red;'>";
        parent::draw($width, $height);
        echo "</div>";
    }
}
$Canvas2 = new Canvas2();
$Canvas2->draw();

对于上面的这种写法,假如我们需要多增加一个一种样式就需要多一个继承。接下来使用装饰器模式(Decorator)就会方便很多。

/*

 * 首先声明一个装饰器的接口

 */

interface DrawDecorator {

    function beforeDraw();

    function afterDraw();

}

接下来再分别添加两个装饰类,来继承接口,实现接口中的方法

/*
 * 颜色装饰
 */
class ColorDrawDecorator implements DrawDecorator {
    protected $color;
    function __construct($color = 'red') {
        $this->color = $color;
    }
    function beforeDraw() {
        echo "<div style='color: {$this->color};'>";
    }
    function afterDraw() {
        echo "</div>";
    }
}
/*
 * 字体大小装饰
 */
class SizeDrawDecorator implements DrawDecorator {
    protected $size;
    function __construct($size = '14px') {
        $this->size = $size;
    }
    function beforeDraw() {
        echo "<div style='font-size: {$this->size};'>";
    }
    function afterDraw() {
        echo "</div>";
    }
}

接下来就是使用我们前面所创建的装饰类

/*
 * 创建一个画布类
 */
class Canvas {
    protected $decorators = array(); //用来存放装饰的数组
    function draw($width = 20, $height = 10) {
        $this->beforeDraw();
        for($i = 0; $i < $height; $i++) {
            for($j = 0; $j < $width; $j++)
            {
                echo '*';
            }
            echo '<br/>';
        }
        $this->afterDraw();
    }
    //添加装饰器的方法
    function addDecorator(DrawDecorator $decorator) {
        $this->decorators[] = $decorator;
    }
    function beforeDraw() {
        foreach($this->decorators as $decorator) {
            $decorator->beforeDraw();
        }
    }
    function afterDraw() {
        $decorators = array_reverse($this->decorators);
        foreach($decorators as $decorator) {
            $decorator->afterDraw();
        }
    }
}
$Canvas = new Canvas();
$Canvas->addDecorator(new ColorDrawDecorator('red'));
$Canvas->addDecorator(new SizeDrawDecorator('9px'));
$Canvas->draw(20, 10);

[!--infotagslink--]

相关文章

  • photoshop设计一幅大鱼海棠动画片海报制作实例教程

    今天小编在这里就来给各位photoshop的这一款软件的使用者们来说一说设计一幅大鱼海棠动画片海报制作的实例教程,各位想知道具体制作步骤的使用者们,那么各位就快来看看...2016-09-14
  • javascript设计模式之解释器模式详解

    神马是“解释器模式”?先翻开《GOF》看看Definition:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。在开篇之前还是要科普几个概念: 抽象语法树: 解释器模式并未解释如...2014-06-07
  • ps怎么制作倒影 ps设计倒影的方法

    ps软件是一款非常不错的图片处理软件,有着非常不错的使用效果。这次文章要给大家介绍的是ps怎么制作倒影,一起来看看设计倒影的方法。 用ps怎么做倒影最终效果&#819...2017-07-06
  • C语言程序设计第五版谭浩强课后答案(第二章答案)

    这篇文章主要介绍了C语言程序设计第五版谭浩强课后答案(第二章答案),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2021-04-02
  • 学习JavaScript设计模式之装饰者模式

    这篇文章主要为大家介绍了JavaScript设计模式中的装饰者模式,对JavaScript设计模式感兴趣的小伙伴们可以参考一下...2016-01-21
  • Photoshop设计商务名片的5种常见思路分享

    今天小编在这里就来给Photoshop的这一款软件的使用者们来说下计商务名片的5种常见思路,各位想知道的使用者,那么下面就快来跟着小编一起看一看吧。 给各位Photosho...2016-09-14
  • WPF实现类似360安全卫士界面的程序源码分享

    最近在网上看到了新版的360安全卫士,感觉界面还不错,于是用WPF制作了一个,时间有限,一些具体的控件没有制作,用图片代替了。感兴趣的朋友一起跟着小编学习WPF实现类似360安全卫士界面的程序源码分享...2020-06-25
  • photoshop安卓和苹果界面设计之尺寸规范详解

    今天小编在这里就来给各位photoshop的这一款软件的使用者们来说下安卓和苹果的界面设计之尺寸规范,各位想知道的使用者们,那么下面就快来跟着小编一起看看吧。 给...2016-09-14
  • photoshop设计重影效果具体制作教程

    今天小编在这里就来给各位photoshop的这一款软件的使用者们来说一说设计重影效果具体的制作教程,各位想知道具体制作方法的软件使用者们,那么大家就来看下小编带来的教...2016-09-14
  • JavaScript设计模式之职责链模式

    这篇文章主要介绍了JavaScript设计模式之职责链模式,对设计模式感兴趣的同学,可以参考下...2021-04-25
  • PS怎么设计T恤 PS制作T恤教程

    PS怎么设计T恤?很多人都想要在T恤上有自己喜欢的图案,那么自己设计T恤的图案是方法之一,本次为大家带来了详细的ps设计T恤教程,有兴趣的同学快来看看吧。 1、打开PS,新...2016-12-31
  • Illustrator结合photoshop设计可爱的卡通女厨师头像制作教程

    今天小编在这里就来给Illustrator的这一款软件的使用者们来说一说结合photoshop设计可爱的卡通女厨师头像的制作教程,各位想知道具体制作步骤的使用者们,那么下面就快来...2016-09-14
  • photoshop设计一张节约用水环保主题海报制作教程

    今天小编在这里就来给photoshop的这一款软件的使用者们来详细的说说设计一张节约用水环保主题海报的制作教程,各位想知道具体制作方法的使用者们,那么下面就快来跟着小...2016-09-14
  • 学习JavaScript设计模式之状态模式

    这篇文章主要为大家介绍了JavaScript设计模式中的状态模式,对JavaScript设计模式感兴趣的小伙伴们可以参考一下...2016-01-12
  • 学习JavaScript设计模式之单例模式

    这篇文章主要为大家介绍了JavaScript设计模式中的单例模式,对JavaScript设计模式感兴趣的小伙伴们可以参考一下...2016-01-21
  • JavaScript设计模式之命令模式

    这篇文章主要介绍了JavaScript设计模式之命令模式,对设计模式感兴趣的同学,可以参考下...2021-04-25
  • c#实现51单片机频率计的代码分享(数字频率计设计)

    c#实现51单片机频率计的代码分享,大家参考使用吧...2020-06-25
  • 学习JavaScript设计模式之责任链模式

    这篇文章主要为大家介绍了JavaScript设计模式中的责任链模式,对JavaScript设计模式感兴趣的小伙伴们可以参考一下...2016-01-21
  • photoshop设计蜘蛛侠纹理文字效果制作教程

    今天小编在这里就来给给各位photoshop的这一款软件的使用者们来说一说设计蜘蛛侠纹理文字效果的制作教程,各位想知道具体制作步骤的使用者们,那么大家下面就来跟着小编...2016-09-14
  • Photoshop设计武侠风毛笔字效果教程

    今天小编在这里就来给Photoshop的这一款软件的使用者们说下设计武侠风毛笔字效果得教程,各位想知道到底该怎么射击制作的使用者们,那么下面就快来跟着小编一起看一看制...2016-09-14