PHP设计模式之:适配器模式入门教程

 更新时间:2016年11月25日 14:56  点击:2077
适配器模式是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设计模式之:注册模式入门教程,希望本文章能够帮助到各位朋友。


当你有一组全局对象被全局访问时可能就需要用到注册模式 (registry),它提供了在程序中有条理的存放并管理对象 (object)一种解决方案。一个“注册模式”应该提供get() 和 set()方法来存储和取得对象。

注册模式通过单一的全局的对象来获取对其它对象的引用 实例:

<?php
/**
 * PHP设计模式之注册模式实例
 *
 
 */
class Registry {
    protected static $objects; //用于存放对象的数组
    /**
     * 将对象放到对象数组上
     * @param string $alias 别名
     * @param object $object 对象
     */
    static function set($alias, $object) {
        self::$objects[$alias] = $object;
    }
 
   /**
    * 将对象从数组上删除
    * @param string $alias 别名
    */
    static function _unset($alias) {
        unset(self::$objects[$alias]);
    }
    /**
     * 通过别名获取对象
     * @param string $alias 别名
     */
    static function get($alias) {
        if (array_key_exists($alias, self::$objects)) {
            return self::$objects[$alias];
        }
    }
}
class MyObject {
    public function test(){
        return 'ok';
    }
}
//结合工厂模式
class MyFactory {
    public static function factory(){
        //返回对象的实例
        $myObject =  new MyObject();
        Registry::set("myObject", $myObject);
    }
}
//调用工厂
MyFactory::factory();
//使用
echo Registry::get("myObject")->test();
Registry::_unset("myObject");
?>

好了,PHP的三种基础模式已经介绍完了,随后博主会继续学习分享PHP的其他设计模式,谢谢!

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开发者都不是很了解了,下面一聚教程小编来为各位整理了一篇相关的文章供各位参考。


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

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

在之后的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 />';
?>

更多的详细说明和实例

[!--infotagslink--]

相关文章

  • 学习JavaScript设计模式之装饰者模式

    这篇文章主要为大家介绍了JavaScript设计模式中的装饰者模式,对JavaScript设计模式感兴趣的小伙伴们可以参考一下...2016-01-21
  • javascript设计模式之解释器模式详解

    神马是“解释器模式”?先翻开《GOF》看看Definition:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。在开篇之前还是要科普几个概念: 抽象语法树: 解释器模式并未解释如...2014-06-07
  • Lua语言新手简单入门教程

    这篇文章主要给大家介绍的是关于Lua语言新手入门的简单教程,文中通过示例代码一步步介绍的非常详细,对各位新手们的入门提供了一个很方便的教程,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。...2020-06-30
  • JavaScript设计模式之职责链模式

    这篇文章主要介绍了JavaScript设计模式之职责链模式,对设计模式感兴趣的同学,可以参考下...2021-04-25
  • C#线程入门教程之单线程介绍

    这篇文章主要介绍了C#线程入门教程之单线程介绍,本文讲解了什么是进程、什么是线程、什么是多线程等内容,并给出了一个单线程代码示例,需要的朋友可以参考下...2020-06-25
  • JavaScript设计模式之命令模式

    这篇文章主要介绍了JavaScript设计模式之命令模式,对设计模式感兴趣的同学,可以参考下...2021-04-25
  • 学习JavaScript设计模式之状态模式

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

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

    这篇文章主要为大家介绍了JavaScript设计模式中的状态模式,对JavaScript设计模式感兴趣的小伙伴们可以参考一下...2016-01-14
  • CocosCreator入门教程之用TS制作第一个游戏

    这篇文章主要介绍了CocosCreator入门教程之用TS制作第一个游戏,对TypeScript感兴趣的同学,一定要看一下...2021-04-16
  • 学习JavaScript设计模式之观察者模式

    这篇文章主要为大家介绍了JavaScript设计模式中的观察者模式,对JavaScript设计模式感兴趣的小伙伴们可以参考一下...2016-01-21
  • 学习JavaScript设计模式之责任链模式

    这篇文章主要为大家介绍了JavaScript设计模式中的责任链模式,对JavaScript设计模式感兴趣的小伙伴们可以参考一下...2016-01-21
  • php入门教程(类实例教程)

    这里主要讲到关于在php教程类的调用,申请明,使用以前各种类的实例方法与操作过程,让你清楚的知道php类的construct destruct clone call wake sleep用法。 简单购物车...2016-11-25
  • 一看就懂的ReactJs基础入门教程-精华版

    现在最热门的前端框架有AngularJS、React、Bootstrap等。自从接触了ReactJS,ReactJs的虚拟DOM(Virtual DOM)和组件化的开发深深的吸引了我,下面来跟我一起领略ReactJs的风采吧~~ 文章有点长,耐心读完,你会有很大收获哦...2021-04-05
  • JavaScript中的设计模式 单例模式

    这篇文章主要给大家介绍的是JavaScript中的单例模式,设计模式代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案,需要的朋友可以参考一下...2021-09-25
  • php入门教程,?号表达式

    下面举一个很简单的?表达式的实现吧,其实它就是简单的if else哦。 <? $a = 5; //定义变数a=5 $b = 3; //定义变数b=5 $c = ($a==$b) ? ("yes") : ("no"); //如果...2016-11-25
  • C# 设计模式系列教程-组合模式

    组合模式可以使客户端调用简单,它可以一致使用组合结构或是其中单个对象,简化了客户端代码。...2020-06-25
  • php入门教程:php rtrim()实例教程

    php入门教程:php rtrim()实例教程 定义和用法 该rtrim ( )函数将删除空格或其他预先确定的性质从右侧的一个字符串。 语法 rtrim(string,charlist) 参数说明 字符...2016-11-25
  • Golang极简入门教程(一):基本概念

    这篇文章主要介绍了Golang极简入门教程(一):基本概念,本文讲解了Golang的基本知识、基础语法、相关术语等,需要的朋友可以参考下...2020-05-01
  • Golang极简入门教程(三):并发支持

    这篇文章主要介绍了Golang极简入门教程(三):并发支持,本文讲解了goroutine线程、channel 操作符等内容,需要的朋友可以参考下...2020-05-01