我们分三篇文章来总结一下设计模式在PHP中的应用,这是第一篇创建型模式。

一、设计模式简介

首先我们来认识一下什么是设计模式:

设计模式是一套被反复使用、容易被他人理解的、可靠的代码设计经验的总结。

设计模式不是Java的专利,我们用面向对象的方法在PHP里也能很好的使用23种设计模式。

那么我们常说的架构、框架和设计模式有什么关系呢?

架构是一套体系结构,是项目的整体解决方案;框架是可供复用的半成品软件,是具体程序代码。架构一般会涉及到采用什么样的框架来加速和优化某部分问题的解决,而好的框架代码里合理使用了很多设计模式。

二、提炼设计模式的几个原则:

开闭原则:模块应对扩展开放,而对修改关闭。

里氏代换原则:如果调用的是父类的话,那么换成子类也完全可以运行。

依赖倒转原则:抽象不依赖细节,面向接口编程,传递参数尽量引用层次高的类。

接口隔离原则:每一个接口只负责一种角色。

合成/聚合复用原则:要尽量使用合成/聚合,不要滥用继承。

三、设计模式的功用?

设计模式能解决

替换杂乱无章的代码,形成良好的代码风格

代码易读,工程师们都能很容易理解

增加新功能时不用修改接口,可扩展性强

稳定性好,一般不会出现未知的问题

设计模式不能解决:

设计模式是用来组织你的代码的模板,而不是直接调用的库;

设计模式并非最高效,但是代码的可读性和可维护性更重要;

不要一味追求并套用设计模式,重构时多考虑;

四、设计模式分类

1、创建型模式:

单例模式、工厂模式(简单工厂、工厂方法、抽象工厂)、创建者模式、原型模式。

2、结构型模式:

适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。

3、行为型模式:

模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。

五、创建型设计模式

1、单例模式

目的:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

应用场景:数据库连接、缓存操作、分布式存储。

 <?php
 /**
  * 优才网公开课示例代码
  *
  * 单例模式
  *
  * @author 优才网全栈工程师教研组
  * @see http://www.ucai.cn
  */

 class DbConn
 {

        private static $_instance = null;
        protected static $_counter = 0;
        protected $_db;

        //私有化构造函数,不允许外部创建实例
        private function __construct()
        {
               self::$_counter += 1;
        }

        public function getInstance()
        {
               if (self::$_instance == null)
               {
                      self::$_instance = new DbConn();
               }
               return self::$_instance;
        }

        public function connect()
        {
               echo "connected: ".(self::$_counter)."n";
               return $this->_db;
        }

 }

 /*
  * 不使用单例模式时,删除构造函数的private后再测试,第二次调用构造函数后,_counter变成2
 */
 // $conn = new DbConn();
 // $conn->connect();
 // $conn = new DbConn();
 // $conn->connect();

 //使用单例模式后不能直接new对象,必须调用getInstance获取
 $conn = DbConn::getInstance();
 $db = $conn->connect();
 //第二次调用是同一个实例,_counter还是1
 $conn = DbConn::getInstance();
 $db = $conn->connect();
 ?>

特别说明:这里getInstance里有if判断然后再生成对象,在多线程语言里是会有并发问题的。例如java的解决方案有二个,给方法加上synchronized关键词变成同步,或者把_instanc的初始化提前放到类成员变量定义时,但是这2种方式php都不支持。不过因为php不支持多线程所以不需要考虑这个问题了。

2、工厂模式

实现:定义一个用于创建对象的接口,让子类决定实例化哪一个类。

应用场景:众多子类并且会扩充、创建方法比较复杂。

<?php
/**
 * 优才网公开课示例代码
 *
 * 工厂模式
 *
 * @author 优才网全栈工程师教研组
 * @see http://www.ucai.cn
 */

//抽象产品
interface Person {
    public function getName();
}
//具体产品实现
class Teacher implements Person {
    function getName() {
        return "老师n";
    }
}
class Student implements Person {
    function getName() {
        return "学生n";
    }
}

//简单工厂
class SimpleFactory {
       public static function getPerson($type) {
              $person = null;
              if ($type == 'teacher') {
                     $person = new Teacher();
              } elseif ($type == 'student') {
                     $person = new Student();
              }
              return $person;
       }
}

//简单工厂调用
class SimpleClient {
       function main() {
              // 如果不用工厂模式,则需要提前指定具体类
              // $person = new Teacher();
              // echo $person->getName();
              // $person = new Student();
              // echo $person->getName();

              // 用工厂模式,则不需要知道对象由什么类产生,交给工厂去决定
              $person = SimpleFactory::getPerson('teacher');
              echo $person->getName();
              $person = SimpleFactory::getPerson('student');
              echo $person->getName();
       }
}

//工厂方法
interface CommFactory {
    public function getPerson();
}
//具体工厂实现
class StudentFactory implements CommFactory {
    function getPerson(){
        return new Student();
    }
}
class TeacherFactory implements CommFactory {
    function getPerson() {
        return new Teacher();
    }
}

//工厂方法调用
class CommClient {
    static function main() {
           $factory = new TeacherFactory();
           echo $factory->getPerson()->getName();
           $factory = new StudentFactory();
           echo $factory->getPerson()->getName();
    }
}

//抽象工厂模式另一条产品线
interface Grade {
       function getYear();
}
//另一条产品线的具体产品
class Grade1 implements Grade {
       public function getYear() {
              return '2003级';
       }
}
class Grade2 implements Grade {
       public function getYear() {
              return '2004级';
       }
}
//抽象工厂
interface AbstractFactory {
       function getPerson();
       function getGrade();
}
//具体工厂可以产生每个产品线的产品
class Grade1TeacherFactory implements AbstractFactory {
       public function getPerson() {
              return new Teacher();
       }
       public function getGrade() {
              return new Grade1();
       }
}
class Grade1StudentFactory implements AbstractFactory {
       public function getPerson() {
              return new Student();
       }
       public function getGrade() {
              return new Grade1();
       }
}
class Grade2TeacherFactory implements AbstractFactory {
       public function getPerson() {
              return new Teacher();
       }
       public function getGrade() {
              return new Grade2();
       }
}
//抽象工厂调用
class FactoryClient {
       function printInfo($factory) {
              echo $factory->getGrade()->getYear().$factory->getPerson()->getName();
       }
       function main() {
              $client = new FactoryClient();
              $factory = new Grade1TeacherFactory();
              $client->printInfo($factory);
              $factory = new Grade1StudentFactory();
              $client->printInfo($factory);
              $factory = new Grade2TeacherFactory();
              $client->printInfo($factory);
       }
}

//简单工厂
//SimpleClient::main();
//工厂方法
//CommClient::main();
//抽象工厂
FactoryClient::main();

?>

三种工厂的区别是,抽象工厂由多条产品线,而工厂方法只有一条产品线,是抽象工厂的简化。而工厂方法和简单工厂相对,大家初看起来好像工厂方法增加了许多代码但是实现的功能和简单工厂一样。但本质是,简单工厂并未严格遵循设计模式的开闭原则,当需要增加新产品时也需要修改工厂代码。但是工厂方法则严格遵守开闭原则,模式只负责抽象工厂接口,具体工厂交给客户去扩展。在分工时,核心工程师负责抽象工厂和抽象产品的定义,业务工程师负责具体工厂和具体产品的实现。只要抽象层设计的好,框架就是非常稳定的。

3、创建者模式

在创建者模式中,客户端不再负责对象的创建与组装,而是把这个对象创建的责任交给其具体的创建者类,把组装的责任交给组装类,客户端支付对对象的调用,从而明确了各个类的职责。

应用场景:创建非常复杂,分步骤组装起来

<?php
/**
 * 优才网公开课示例代码
 *
 * 创建者模式
 *
 * @author 优才网全栈工程师教研组
 * @see http://www.ucai.cn
 */

//购物车
class ShoppingCart {
       //选中的商品
    private $_goods = array();
    //使用的优惠券
    private $_tickets = array();

       public function addGoods($goods) {
              $this->_goods[] = $goods;
       }

    public function addTicket($ticket) {
           $this->_tickets[] = $ticket;
    }

    public function printInfo() {
           printf("goods:%s, tickets:%sn", implode(',', $this->_goods), implode(',', $this->_tickets));
    }
}

//假如我们要还原购物车的东西,比如用户关闭浏览器后再打开时会根据cookie还原
$data = array(
       'goods' => array('衣服', '鞋子'),
       'tickets' => array('减10'),
);

//如果不使用创建者模式,则需要业务类里一步步还原购物车
// $cart = new ShoppingCart();
// foreach ($data['goods'] as $goods) {
//   $cart->addGoods($goods);
// }
// foreach ($data['tickets'] as $ticket) {
//   $cart->addTicket($ticket);
// }
// $cart->printInfo();
// exit;

//我们提供创建者类来封装购物车的数据组装
class CardBuilder {
       private $_card;
       function __construct($card) {
              $this->_card = $card;
       }
       function build($data) {
              foreach ($data['goods'] as $goods) {
                     $this->_card->addGoods($goods);
              }
              foreach ($data['tickets'] as $ticket) {
                     $this->_card->addTicket($ticket);
              }
       }
       function getCrad() {
              return $this->_card;
       }
}

$cart = new ShoppingCart();
$builder = new CardBuilder($cart);
$builder->build($data);
echo "after builder:n";
$cart->printInfo();

?>

可以看出,使用创建者模式对内部数据复杂的对象封装数据组装过程后,对外接口就会非常简单和规范,增加修改新数据项也不会对外部造成任何影响。

3、 原型模式

用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。

应用场景: 类的资源非常多、性能和安全要求,一般和工厂方法结合使用。

<?php
/**
 * 优才网公开课示例代码
 *
 * 原型模式
 *
 * @author 优才网全栈工程师教研组
 * @see http://www.ucai.cn
 */

//声明一个克隆自身的接口
interface Prototype {
    function copy();
}   

//产品要实现克隆自身的操作
class Student implements Prototype {
       //简单起见,这里没有使用get set
    public $school;
    public $major;
       public $name;

       public function __construct($school, $major, $name) {
              $this->school = $school;
              $this->major = $major;
              $this->name = $name;
       }

       public function printInfo() {
              printf("%s,%s,%sn", $this->school, $this->major, $this->name);
       }

    public function copy() {
           return clone $this;
    }
}

$stu1 = new Student('清华大学', '计算机', '张三');
$stu1->printInfo();

$stu2 = $stu1->copy();
$stu2->name = '李四';
$stu2->printInfo();

?>

这里可以看到,如果类的成员变量非常多,如果由外部创建多个新对象再一个个赋值,则效率不高代码冗余也容易出错,通过原型拷贝复制自身再进行微小修改就是另一个新对象了。

设计模式的第一部分,创建型模式就总结完了。下面还有两部分结构型设计模式和行为型设计模式稍后继续。

视频链接:http://www.ucai.cn/opencourse/98?f=10

php设计模式(一):简介及创建型模式的更多相关文章

  1. Java设计模式(5)——创建型模式之建造者模式(Builder)

    一.概述 概念 将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示.(与工厂类不同的是它用于创建复合对象) UML图   主要角色 抽象建造者(Builder)——规范建造方法与结果 ...

  2. Java设计模式(4)——创建型模式之单例模式(Singleton)

    一.概述 弥补一下之前没有给设计模式下的定义,先介绍一下设计模式(引用自百度百科): 设计模式(Design Pattern)是一套被反复使用.多数人知晓的.经过分类的.代码设计经验的总结. 使用设计 ...

  3. Java设计模式(3)——创建型模式之抽象工厂模式(Abstract Factory)

    一.概述 抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式.抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体情况下,创建多个产品族中的产品对象. UML图: 其他的过多概念不再 ...

  4. Java设计模式(2)——创建型模式之工厂方法模式(Factory Method)

    一.概述 上一节[简单工厂模式]介绍了通过工厂创建对象以及简单的利弊分析:这一节来看看工厂方法模式对类的创建 工厂方法模式: 工厂方法与简单工厂的不同,主要体现在简单工厂的缺点的改进: 工厂类不再负责 ...

  5. Java设计模式(1)——创建型模式之简单工厂模式(Simple Factory)

    设计模式系列参考: http://www.cnblogs.com/Coda/p/4279688.html 一.概述 工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高 ...

  6. Java设计模式03:常用设计模式之单例模式(创建型模式)

    1.  Java之单例模式(Singleton Pattern ) 单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例.饿汉式单例.登记式单例三种. 单例模式有一下特点: 1.单例类只能有一个实 ...

  7. Java设计模式(6)——创建型模式之原型模式(Prototype)

    一.概述 概念 // 引用自<Java与模式> UML图 第二种:登记式 二.实践 先导知识 对象的拷贝: 直接赋值:此时只是相当于a1,a2指向同一个对象,无论哪一个操作的都是同一个对象 ...

  8. C#面向对象设计模式纵横谈——2.Singleton 单件(创建型模式)

    一:模式分类 从目的来看: 创建型(Creational)模式:负责对象创建. 结构型(Structural)模式:处理类与对象间的组合. 行为型(Behavioral)模式:类与对象交互中的职责分配 ...

  9. Java设计模式之创建型模式

    创建型模式分为五类:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式 一.工厂方法模式:接口-实现类.工厂类

随机推荐

  1. 第十三章:降维:主成分分析PCA

  2. ENVI【非监督分类】

    非监督分类的概念: 非监督分类,又称“聚类分析或者点群分析”.在多光谱图像中搜寻.定义其自然相似光谱集群的过程.它不必对图像地物获取先验知识,仅依靠图像上不同地物光谱信息进行特征提取,在统计特征的差别 ...

  3. set方法内存分析

    // //  main.m //  04-set方法的内存管理分析 // //  Created by apple on 14-3-17. // // #import <Foundation/F ...

  4. JS动态广告浏览

    <script language="JavaScript"> function addEventSimple(obj,evt,fn){ if(obj.addEventL ...

  5. IOS 支付功能的实现

    支付宝是第三方支付平台,简单来说就是协调客户,商户,银行三者关系的方便平台 使用支付宝进行一个完整的支付功能,大致有以下步骤: a 与支付宝进行签约,获得商户ID(partner)和账号ID(sell ...

  6. 线程本地变量ThreadLocal

    一.本地线程变量使用场景 并发应用的一个关键地方就是共享数据.如果你创建一个类对象,实现Runnable接口,然后多个Thread对象使用同样的Runnable对象,全部的线程都共享同样的属性.这意味 ...

  7. Web开发,如何从小工到专家

    最近在研读关于“整体性学习”的一些东西,收获颇丰. 整体性学习强调的东西有三样:结构.模型.与高速通道.特别是关于结构的篇章: 理解是什么?理解就是结构高度发达完善的结果. 是不是有些学科你可以轻松“ ...

  8. jquery扩展方法案例

    -----------------扩展方法: $.extend({ "max": function (a, b) { if (a > b) return a; }, &quo ...

  9. Java的Random总结

    /** * @Title:RandomNum.java * @Package:com.yhd.chart.model * @Description:Java产生随机数 * @author:Youhai ...

  10. jsonArray返回

    dao <select id="selectShopInfo" resultType="java.util.HashMap"> SELECT * F ...