龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > web编程 > php编程 >

代码均来源于《PHP设计模式》一书(二)

时间:2014-07-22 14:51来源: 作者: 点击:
分享到:
前一篇文章主要是完成第六章到第十二章的代码编写及测试。本篇代码分享将完成后期代码的陆续分享。br / 虽然仅是摘抄书本的东西,但是好好的理解这些用例,对于我们实际工作中还
前一篇文章主要是完成第六章到第十二章的代码编写及测试。本篇代码分享将完成后期代码的陆续分享。
虽然仅是摘抄书本的东西,但是好好的理解这些用例,对于我们实际工作中还是或多或少会带来一些帮助。
(注: 本例用到的数据库数据在 http://www.oschina.net/code/snippet_167160_7203 可以下载)

感谢 开源社区 提供这样一个平台让我们相互认识。

<?php 
/**
 * 转自 《PHP设计模式》 第十三章: 观察者模式
 * 1. 观察者:能够更便利地创建查看目标对象状态的对象,并且提供与核心对象非耦合的指定功能性
 * 2. 在创建其核心功能可能包含可观察状态变化的对象时候,最佳的做法是基于观察者设计模式创建于目标对象
 *    进行交互的其他类
 * 3. 常见的观察者设计模式示例有:插件系统,RSS源缓存器构建
 *
 */
//被观察者: 基础CD类
class CD {
	
	public $title = "";
	public $band  = "";
	protected $_observers = array();   // 观察者对象数组
	
	public function __construct($title, $band) {
		$this->title = $title;
		$this->band  = $band;
	}
	
	public function attachObserver($type, $observer) {
		$this->_observers[$type][] = $observer;
	}
	
	public function notifyObserver($type) {
		if (isset($this->_observers[$type])) {
			foreach ($this->_observers[$type] as $observer) {
				$observer->update($this);
			}
		}
	}
	
	public function buy() {
		$this->notifyObserver("purchased");
	}
}

//观察者类 后台处理
class buyCDNotifyStreamObserver {
	public function update(CD $cd) {
		$activity  = "The CD named {$cd->title} by ";
		$activity .= "{$cd->band} was just purchased.";
		activityStream::addNewItem($activity);
	}
}

//消息同事类 前台输出
class activityStream {
	public function addNewItem($item) {
		print $item;
	}
}

//测试实例
$title = "Waste of a Rib";
$band  = "Never Again";

$cd    = new CD($title, $band);

$observer = new buyCDNotifyStreamObserver();

$cd->attachObserver("purchased", $observer);
$cd->buy();
 
/* End of Observer.class.php */
/* Location the file Design/Observer.class.php */

2. [文件] Prototype.class.php ~ 1KB     下载(27)     跳至 [1] [2] [3] [4] [5] [6] [7] [全屏预览]

<?php
/**
 * 转自 《PHP设计模式》 第十四章: 原型模式
 * 原型:原型设计模式创建对象的方式是复制和克隆初始对象或原型,这种方式比创建新实例更为有效。
 *
 */
//初始CD类
class CD {
	
	public $title = "";
	public $band  = "";
	public $trackList = array();
	public function __construct($id) {
		$handle = mysql_connect("localhost", "root", "root");
		mysql_select_db("test", $handle);
		
		$query  = "select * from cd where id = {$id}";
		$results= mysql_query($query, $handle);
		
		if ($row = mysql_fetch_assoc($results)) {
			$this->band  = $row["band"];
			$this->title = $row["title"];
		}
	}
	
	public function buy() {
		var_dump($this);
	}
}

//采用原型设计模式的混合CD类, 利用PHP的克隆能力。
class MixtapeCD extends CD {
	public function __clone() {
		$this->title = "Mixtape";
	}
}

//示例测试
$externalPurchaseInfoBandID = 1;
$bandMixproto = new MixtapeCD($externalPurchaseInfoBandID);

$externalPurchaseInfo   = array();
$externalPurchaseInfo[] = array("brrr", "goodbye");
$externalPurchaseInfo[] = array("what it means", "brrr");

//因为使用克隆技术, 所以每个新的循环都不需要针对数据库的新查询。
foreach ($externalPurchaseInfo as $mixed) {
	$cd = clone $bandMixproto;
	$cd->trackList = $mixed;
	$cd->buy();
}

/* End of Prototype.class.php */
/* Location the file Design/Prototype.class.php */

3. [文件] Proxy.class.php ~ 2KB     下载(28)     跳至 [1] [2] [3] [4] [5] [6] [7] [全屏预览]

<?php
/** 
 * 转自 《PHP设计模式》 第十五章: 代理模式
 * 代理: 构建了透明置于两个不同对象之内的一个对象,从而能够截取或代理这两个对象间的通信或访问
 * 在需要截取两个对象之间的通信时,最佳的做法是使用一个基于代理设计模式的新对象
 * 
 */
//基础CD类
class CD {
	
	protected $_title  = "";
	protected $_band   = "";
	protected $_handle = NULL;
	
	public function __construct($title, $band) {
		$this->_title = $title;
		$this->_band  = $band;
	}
	
	public function buy() {
		$this->_connect();
		
		$query  = "update cd set bought = 1 where band = '";
		$query .= mysql_real_escape_string($this->_band, $this->_handle);
		$query .= " ' and title = '";
		$query .= mysql_real_escape_string($this->_title, $this->_handle);
		$query .= "'";
		
		mysql_query($query, $this->_handle);
		
		//var_dump("success");
	}
	
	protected function _connect() {
		$this->_handle = mysql_connect("localhost", "root", "root");
		mysql_select_db("test", $this->_handle);
	}
}

//现在我们需要访问位于德克萨斯州达拉斯某处的数据, 这就要求一个具有访问性能的Proxy对象, 
//该对象需要截取与本地数据库的链接, 转而链接到达拉斯网络运营中心。

//代理类
class DallasNoCCDProxy extends CD {
	protected function _connect() {
		$this->_handle = mysql_connect("dallas", "user", "pass");
		mysql_select_db("test", $this->_handle);
	}
}

//测试实例
$enternalTitle = "Waster of a Rib";
$externalBand  = "Neve Again";

$cd = new CD($enternalTitle, $externalBand);
$cd->buy();

$dallasCD = new DallasNoCCDProxy($enternalTitle, $externalBand);
$dallasCD->buy();
 
/* End of Proxy.class.php */
/* Location the file Design/Proxy.class.php */

4. [文件] Adapter.class.php ~ 3KB     下载(24)     跳至 [1] [2] [3] [4] [5] [6] [7] [全屏预览]

<?php
/**
 * 转自《PHP设计模式》 第三章 适配器模式
 * 适配器:只是讲某个对象的接口适配为另一个对象所期望的接口
 * 记住: 在须要转化一个对象的接口用于另一个对象时候,实现Adapter对象不仅仅是最佳做法,而且还能减少很多麻烦
 *
 */
/**
 * 代码示例 - 背景介绍
 * 在项目最初的代码库中,名为errorObject 的对象能够处理所有错误的消息和代码。 
 * 并且通过logToConsole对象将错误消息及代码输出到控制台; 新的需求中需要要求
 * 将错误记录到一个多列CSV文件中,要求第一列是错误代码,第二列是错误消息文本
 *
 */
//早期的errorObject类
class errorObject {
	
	private $_error;
	
	public function __construct($error) {
		$this->_error = $error;
	}
	
	public function getError() {
		return $this->_error;
	}
}

//早期的错误信息代码输出至控制台处理类: logToConsole
class logToConsole {
	
	private $_errorObject;
	
	public function __construct($errorObject) {
		$this->_errorObject = $errorObject;
	}
	
	public function write() {
		fwrite(STDERR, $this->_errorObject->getError());
	}
}

//早期的测试实例 (备注:需要在命令行模式输入:php Design/Adapter.class.php)
$error = new errorObject("404:Not Found");
$log   = new logToConsole($error);
$log->write();

//后期更新处理:错误代码输出至CSV文件类: logToCSV
//注意: 新增 getErrorNumber() 和 getErrorText() 方法
class logToCSV {
	
	const CSV_LOCATION = "log.csv";
	
	private $_errorObject;
	
	public function __construct($errorObject) {
		$this->_errorObject = $errorObject;
	}
	
	public function write() {
		$line  = $this->_errorObject->getErrorNumber();
		$line .= ",";
		$line .= $this->_errorObject->getErrorText();
		$line .= "\n";
		
		file_put_contents(self::CSV_LOCATION, $line, FILE_APPEND);
	}
}

//针对以上问题,我们可以采用以下两种办法解决
//1. 更新现有代码库中的errorObject类,新增 getErrorNumber() 和 getErrorText() 方法
//2. 创建一个Adapter对象

//我们采用解决方案2实现 
class logToCSVAdapter extends errorObject {
	
	private $_errorNumber;
	private $_errorText;
	
	public function __construct($error) {
		parent::__construct($error);
		
		$parts = explode(":", $this->getError());
		
		$this->_errorNumber = $parts[0];
		$this->_errorText   = $parts[1];
	}
	
	public function getErrorNumber() {
		return $this->_errorNumber;
	}
	
	public function getErrorText() {
		return $this->_errorText;
	}
}

//测试实例
$error = new logToCSVAdapter("404:Not Found");
$log   = new logToCSV($error);
$log->write();

/* End of Adapter.class.php */
/* Location the file Design/Adapter.class.php */

5. [文件] Builder.class.php ~ 2KB     下载(26)     跳至 [1] [2] [3] [4] [5] [6] [7] [全屏预览]

<?php
/**
 * 转自《PHP设计模式》 第四章: 建造者模式
 * 建造者: 定义了处理其他对象的复杂构建的对象设计
 * 建造者设计模式的目的是消除其他对象的复杂构建过程,使用建造者设计
 * 模式不仅仅是最佳的做法,而且在某个对象的构造和配置方法改变时可以
 * 尽可能地减少重复更改代码
 * 
 */
class product {
	
	protected $_type  = "";
	protected $_size  = "";
	protected $_color = "";
	
	public function setType($type) {
		$this->_type = $type;
	}
	
	public function setSize($size) {
		$this->_size = $size;
	}
	
	public function setColor($color) {
		$this->_color = $color;
	}
}

//常规的处理:我们会将产品配置分别传递给产品类的每个方法
//$productConfig = array("type" => "shirt", "size" => "XL", "color" => "red");
//$product = new product();
//$product->setType($productConfig["type"]);
//$product->setSize($productConfig["size"]);
//$product->setColor($productConfig["color"]);

//但是良好的建议是使用基于建造者设计模式的对象来创建这个产品实例

class productBuilder {
	
	protected $_product = NULL;
	protected $_configs = array();
	
	public function __construct($configs) {
		$this->_product = new product();
		$this->_configs = $configs;
	}
	
	public function build() {
		$this->_product->setType($this->_configs["type"]);
		$this->_product->setSize($this->_configs["size"]);
		$this->_product->setColor($this->_configs["color"]);
	}
	
	public function getProduct() {
		return $this->_product;
	}
	
}

//测试实例
$productConfigs = array("type" => "shirt", "size" => "XL", "color" => "red");
$builder        = new productBuilder($productConfigs);
$builder->build();
var_dump($builder->getProduct());

/* End of Builder.class.php */
/* Location the file Desing/Builder.class.php */

6. [文件] SinglnInstance.class.php ~ 2KB     下载(26)     跳至 [1] [2] [3] [4] [5] [6] [7] [全屏预览]

<?php
/**
 * 转自《PHP设计模式》 第十六章 单元素模式
 * 单元素: 通过提供对自身共享实例的访问, 单元素设计模式用于限制特定对象只能被创建一次
 * 单元素设计模式最常用于构建数据库连接对象。 
 *
 */
/**
 * 代码示例 - 背景介绍
 * 利用单元素设计模式连接数据库并完成CD库存表记录更新
 *
 */
//利用单元素设计模式编写的库存记录更新表
class InventoryConnection {
	
	protected static $_instance = NULL;		//注意这个 static 的定义
	
	protected $_handle = NULL;
	
	public static function getInstance() {	//注意这个 static 的定义
		if ( ! self::$_instance instanceof self) {
			self::$_instance = new self;
		}
		
		return self::$_instance;
	}
	
	protected function __construct() {
		$this->_handle = mysql_connect("localhost", "root", "root");
		mysql_select_db("test", $this->_handle);
	}
	
	public function updateQuantity($band, $title, $number) {
		$query  = " update cd set amount = (amount + ". intval($number) . ")";
		$query .= " where band = '";
		$query .= mysql_real_escape_string($band);
		$query .= "'";
		$query .= " and title = '";
		$query .= mysql_real_escape_string($title);
		$query .= "'";
		
		mysql_query($query, $this->_handle);
	}
}

//基本CD类
class CD {
	
	protected $_title = "";
	protected $_band  = "";
	
	public function __construct($title, $band) {
		$this->_title = $title;
		$this->_band  = $band;
	}
	
	public function buy() {
		$inventory = InventoryConnection::getInstance();
		$inventory->updateQuantity($this->_band, $this->_title, -1);
	}	
}

//测试实例
$boughtCDs   = array();
$boughtCDs[] = array("band" => "Never Again", "title" => "Waster of a Rib");
$boughtCDs[] = array("band" => "Therapee", "title" => "Long Road");

//因为会多次利用$cd执行buy操作, 所以在其buy方法具体实现的InventoryConnection对象
//最好是单元素对象。
//针对每个被购买的CD都打开一个与数据库的新连接并不是一个好做法。
foreach ($boughtCDs as $boughtCD) {
	$cd = new CD($boughtCD['title'], $boughtCD['band']);
	$cd->buy();
}

/* End of SingleInstance.class.php */
/* Location the file Design/SingleInstance.class.php */

7. [文件] Strategy.class.php ~ 2KB     下载(25)     跳至 [1] [2] [3] [4] [5] [6] [7] [全屏预览]

<?php
/**
 * 转自《PHP设计模式》 第十七章 策略模式
 * 策略模式: 帮助构建的对象不必自身包含逻辑,而是根据需要利用其它对象中的算法
 *
 * 注: 与第七章的委托模式进行对比阅读
 * 
 */
/**
 * 代码示例 - 背景介绍
 * 灵活的让对象生成 XML 或 JSON 字符串输出。
 * 
 */
//基准的 Strategy 对象类
class CDusersStrategy {
	
	public $title = "";
	public $band  = "";
	
	protected $_strategy;
	
	public function __construct($title, $band) {
		$this->title = $title;
		$this->band  = $band;
	}
	
	public function setStrategyContext($strategyObject) {
		$this->_strategy = $strategyObject;
	}
	
	public function get() {
		return $this->_strategy->get($this);
	}
	
}

//创建用于 XML 的 Strategy 对象类
class CDAsXMLStrategy {
	
	public function get(CDusersStrategy $cd) {
		$doc  = new DomDocument();
		$root = $doc->createElement("CD");
		$root = $doc->appendChild($root);
		
		$title = $doc->createElement("TTILE", $cd->title);
		$title = $root->appendChild($title);
		
		$band = $doc->createElement("BAND", $cd->band);
		$band = $root->appendChild($band);
		
		return $doc->saveXML();
	}
}

//创建用于 JSON 的 Strategy 对象类 
class CDAsJSONStrategy {
	
	public function get(CDusersStrategy $cd) {
		$json = array();
		$json["CD"]["title"] = $cd->title;
		$json["CD"]["band"]  = $cd->band;
		
		return json_encode($json);
	}
}

//创建其它格式输出的 Strategy 对象类
class CDAsOtherStrategy {
	
	public function get(CDusersStrategy $cd) {
		//依据实际情况编写代码
	}
}

//测试实例
$externalTitle = "Never Again";
$externalBand  = "Waste of a Rib";

$cd = new CDusersStrategy($externalTitle, $externalBand);

//XML output
$cd->setStrategyContext(new CDAsXMLStrategy());
print $cd->get();

//JSON output
$cd->setStrategyContext(new CDAsJSONStrategy());
print $cd->get();

/* End of Strategy.class.php */
/* Location the file Design/Strategy.class.php */
精彩图集

赞助商链接