PHP设计模式(四)原型模式Prototype实例详解【创建型】 |
|
本文实例讲述了PHP设计模式:原型模式Prototype 。分享给大家供大家参考,具体如下: 1. 概述我们都知道,创建型模式一般是用来创建一个新的对象,然后我们使用这个对象完成一些对象的操作,我们通过原型模式可以快速的创建一个对象而不需要提供专门的new()操作就可以快速完成对象的创建,这无疑是一种非常有效的方式,快速的创建一个新的对象 。 例子1:孙悟空拔下一嘬猴毛,轻轻一吹就会变出好多的孙悟空来 。 例子2:寄个快递 下面是一个邮寄快递的场景: 2. 问题当对象的构造函数非常复杂,在生成新对象的时候非常耗时间、耗资源的情况?我们是怎么来创建呢? 3. 解决方案通过复制(克隆、拷贝)一个指定类型的对象来创建更多同类型的对象 。这个指定的对象可被称为“原型”对象,也就是通过复制原型对象来得到更多同类型的对象 。即原型设计模式 。在php的很多模板库,都用到clone 。如smarty等 。 4. 适用性原型模式的主要思想是基于现有的对象克隆一个新的对象出来,一般是有对象的内部提供克隆的方法,通过该方法返回一个对象的副本,这种创建对象的方式,相比我们之前说的几类创建型模式还是有区别的,之前的讲述的工厂模式与抽象工厂都是通过工厂封装具体的new操作的过程,返回一个新的对象,有的时候我们通过这样的创建工厂创建对象不值得,特别是以下的几个场景的时候,可能使用原型模式更简单也效率更高 。 • 1)当一个系统应该独立于它的产品创建、构成和表示时,要使用 Prototype模式 • 2)当要实例化的类是在运行时刻指定时,例如,通过动态装载; • 3)为了避免创建一个与产品类层次平行的工厂类层次时 • 4)当一个类的实例只能有几个不同状态组合中的一种时 。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些 。(也就是当我们在处理一些对象比较简单,并且对象之间的区别很小,可能只是很固定的几个属性不同的时候,可能我们使用原型模式更合适) 。 5. 结构原型模式结构如下页上图所示:
6. 组成客户(Client)角色:使用原型对象的客户程序 7. 效果Prototype模式有许多和Abstract Factory模式 和 Builder模式一样的效果:它对客户隐藏了具体的产品类,因此减少了客户知道的名字的数目 。此外,这些模式使客户无需改变即可使用与特定应用相关的类 。 下面列出Prototype模式的另外一些优点 。 1 ) 运行时刻增加和删除产品: Prototype允许只通过客户注册原型实例就可以将一个新的具体产品类并入系统 。它比其他创建型模式更为灵活,因为客户可以在运行时刻建立和删除原型 。 Prototype的主要缺陷是每一个Prototype的子类都必须实现clone操作,这可能很困难 。 8. 实现
<?php
/**
* 原型模式
*/
/**
* 抽象原型角色
*/
interface Prototype {
public function copy();
}
/**
* 具体原型角色
*/
class ConcretePrototype implements Prototype{
private $_name;
public function __construct($name) {
$this->_name = $name;
}
public function setName($name) {
$this->_name = $name;
}
public function getName() {
return $this->_name;
}
public function copy() {
/** 深拷贝 */
return clone $this;
/** 浅拷贝 */
//return $this;
}
}
class Client {
/**
* Main program.
*/
public static function main() {
$object1 = new ConcretePrototype(11);
$object_copy = $object1->copy();
var_dump($object1->getName());
echo '<br />';
var_dump($object_copy->getName());
echo '<br />';
$object1->setName(22);
var_dump($object1->getName());
echo '<br />';
var_dump($object_copy->getName());
echo '<br />';
}
}
Client::main();
?>
9. 浅拷贝和深拷贝原型模式的原理图:
浅拷贝 被拷贝对象的所有变量都含有与原对象相同的值,而且对其他对象的引用仍然是指向原来的对象 。即浅拷贝只负责当前对象实例,对引用的对象不做拷贝 。 浅复制后的对象和对象副本的情况:
深拷贝 被拷贝对象的所有的变量都含有与原来对象相同的值,除了那些引用其他对象的变量 。那些引用其他对象的变量将指向一个被拷贝的新对象,而不再是原有那些被引用对象 。即 深拷贝把要拷贝的对象所引用的对象也都拷贝了一次,而这种对被引用到的对象拷贝叫做间接拷贝 。 深复制的对象和对象副本的情况:
深拷贝要深入到多少层,是一个不确定的问题 。 在决定以深拷贝的方式拷贝一个对象的时候,必须决定对间接拷贝的对象是采取浅拷贝还是深拷贝还是继续采用深拷贝 。 因此,在采取深拷贝时,需要决定多深才算深 。此外,在深拷贝的过程中,很可能会出现循环引用的问题 。 10. 带Prototype Manager的原型模式原型模式的第二种形式是带原型管理器的原型模式,其UML图如下:
原型管理器(Prototype Manager)角色:创建具体原型类的对象,并记录每一个被创建的对象 。 下面这个例子演示了在原型管理器中存储用户预先定义的颜色原型,客户通过原型管理器克隆颜色对象 。
<?php
/**
* abstract Prototype
*
*/
abstract class ColorPrototype
{
//Methods
abstract function copy();
}
/**
* Concrete Prototype
*
*/
class Color extends ColorPrototype{
//Fields
private $red;
private $green;
private $blue;
//Constructors
function __construct( $red, $green, $red) {
$this->red = $red;
$this->green = $green;
$this->blue = $red;
}
/**
* set red
*
* @param unknown_type $red
*/
public function setRed($red) {
$this->red = $red;
}
/**
* get red
*
*/
public function getRed(){
return $this->red;
}
/**
*set Green
*
* @param $green
*/
public function setGreen($green) {
$this->green = $green;
}
/**
* get Green
*
* @return unknown
*/
public function getGreen() {
return $this->green ;
}
/**
*set Blue
*
* @param $Blue
*/
public function setBlue($Blue) {
$this->blue = $Blue;
}
/**
* get Blue
*
* @return unknown
*/
public function getBlue() {
return $this->blue ;
}
/**
* Enter description here...
*
* @return unknown
*/
function copy(){
return clone $this;
}
function display() {
echo $this->red , ',', $this->green, ',', $this->blue ,'<br>';
}
}
/**
* Enter description here...
*
*/
class ColorManager
{
// Fields
static $colors = array();
// Indexers
public static function add($name, $value){
self::$colors[$name] = $value;
}
public static function getCopy($name) {
return self::$colors[$name]->copy();
}
}
/**
*Client
*
*/
class Client
{
public static function Main()
{
//原型:白色
ColorManager::add("white", new Color( 255, 0, 0 ));
//红色可以由原型白色对象得到,只是重新修改白色: r
$red = ColorManager::getCopy('white');
$red->setRed(255);
$red->display();
//绿色可以由原型白色对象得到,只是重新修改白色: g
$green = ColorManager::getCopy('white');
$green->setGreen(255);
$green->display();
//绿色可以由原型白色对象得到,只是重新修改白色: b
$Blue = ColorManager::getCopy('white');
$Blue->setBlue(255);
$Blue->display();
}
}
ini_set('display_errors', 'On');
error_reporting(E_ALL & ' E_DEPRECATED);
Client::Main();
?>
更多关于PHP相关内容感兴趣的读者可查看本站专题:《php面向对象程序设计入门教程》、《PHP数组(Array)操作技巧大全》、《PHP基本语法入门教程》、《PHP运算与运算符用法总结》、《php字符串(string)用法总结》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》 希望本文所述对大家PHP程序设计有所帮助 。 |