永远的学生

qindgfly

导航

zen-cart开发教程 - 通知者/观察者模式

      通过重写机制和自动加载机制, Zen-Cart使得二次开发人员能够很方便的向核心代码中增加自己的功能, 然而开发者并不能在不破坏原始代码的基础上随意向Zen-Cart核心代码中的不同地方增加自己的代码. 因此, Zen-Cart引入了通知者/观察者模式(observer/notifier system, ONS), 这给开发人员提供了访问Zen-Cart核心代码, 而不需要破坏其原始文件内容的方式.

    第1节  基类base

      为了实现通知者/观察者模式, 首先引入一个重要的类: base类(class.base.php).

      base类中包含了实现通知者/观察者模式的代码,  因此为了使通知者/观察者模式生效, Zen-Cart中的所有类都被定义为base类的子类, 任意打开一个类文件, 例如language.php,你讲可以看到如所示的代码.  如果你希望你自己的类也能够实现通知者/观察这模式, 请将你的类从base类派生.

class language extends base {
.

    第2节   通知者

      ONS的意图是, 开发者可以写代码, 来等待特定的事件发生, 一旦事件发生, 就执行自己的代码. 那么这些事件如何定义, 什么时候触发呢?

      事件可以通过如下面所示的代码来进行触发.

$this->notify('EVENT_NAME');

 

    第3节   观察者

      事件已经触发了, 可是这对开发者而言又有何用呢? 为了利用通知者的事件, 我们必须编写代码来监听这些事件. 一般而言, 我们需要将观察者编写成一个类, 并放到目录” includes/classes/observers”下面. 下面, 我们就来看一下如何写一个监听事件的观察者类.

 

<?php
class myObserver extends base {
function myObserver() {
$this->attach($this, array('NOTIFIER_CART_ADD_CART_END'));
}
function update(&$callingClass, $notifier, $paramsArray) {
... do some stuff
}
}

 

 

      从代码中, 可以看到, 我们定义了一个名为myObserver的类, 并且在构造函数中将myObserver类和事件NOTIFIER_CART_ADD_CARD_END(shopping_cart.php)进行了绑定.

当某个事件被触发时, base类将检测是否有观察者类在监听这个事件, 如果有, base类将执行观察者类中的一个方法,  在这里当NOTIFIER_CART_ADD_CARD_END事件被触发后, update方法将会被执行.

     参数说明:

     attach方法.

         &$observer  - 观察者类的引用, 为新的观察者生成一个唯一的ID

         $eventIDArray  -  要监听的事件数组

     update 方法

         &$callingClass – 触发事件的类的引用, 你可以通过该参数访问类中的变量

         $notifier – 触发update通知者名称, 因为可能会监听到多个通知者触发事件

         $paramsArray – 传递的参数, 通知这可能利用该参数向观察者提供一些参数

 

    第4节   notifier类

      ONS是面向对象的思想而设计, 观察者期望将自己绑定到一个可以在自己方法中进行通知的类, 然而在Zen-Cart中的很多程序事实上并不包含在类中, 例如页面中的代码. 为了使在一般的程序中也能够进行事件的通知, Zen-Cart设计了一个notifier类, 作为全局的一个通知者. 如果你想创建一个类来监听在程序中(例如页面头部文件中的代码)触发的事件, 就应该将notifier加入myObserver类, 如下面代码所示.

 

class myObserver extends base {
function myObserver() {
global $zco_notifier;
$zco_notifier->attach($this, array('NOTIFY_HEADER_END_CHECKOUT_CONFIRMATION'));
}

 

    第5节   包含观察者类文件

     值得注意的是”includes/classes/observersdirectory”目录中的文件并不会自动加载, 所以你需要让application_top.php文件能够自动加载myObserver类.在目录” includes/auto_loaders”中增加一个文件”config.freeProduct.php”,文件内容如表格 3‑4 代码所示.

 

$autoLoadConfig[10][] = array('autoType'=>'class',
'loadFile'=>'observers/class.freeProduct.php');
$autoLoadConfig[90][] = array('autoType'=>'classInstantiate',
'className'=>'freeProduct',
'objectName'=>'freeProduct');

 

    第6节   通知者/观察者模式编程实例

      有时会遇到的一种需求是, 当客户购买了一定数额的商品后, 如果购买的总金额超过指定的数量, 我们希望给客户一个免费的小赠品.

      通过分析后, 可以知道, 当客户增加了商品到购物车后, 会检测是否购买的数量超过了指定的最低消费数量, 则应该自动将该礼品加到客户的购物车, 而如果客户删掉了购物车中的商品, 同样也需要检测, 如果消费总数量已经小于了最低消费数量了, 则应该自动将该礼品从购物车中删除. 按照传统的编程方式, 要实现这个功能也不难, 但是这将在多处对Zen-Cart的核心代码产生破坏. 现在通过ONS, 我们可以通过一个很简单的自定义类来完成这个功能, 并且不会破坏Zen-Cart的核心代码.

 

通知者/观察者编程实例
<?php
/**
* Observer class used to add a free product to the cart if the user spends more than $x
*
*/
class freeProduct extends base {
/**
* The threshold amount the customer needs to spend.
* 客户需要消费的总数
* Note this is defined in the shops base currency, and so works with multi currency shops
*
* @var decimal
*/
var $freeAmount = 50;
/**
* The id of the free product.
* 赠品的ID
* Note. This must be a true free product. e.g. price = 0 Also make sure that if you don't want the customer
* to be charged shipping on this, that you have it set correctly.
*
* @var integer
*/
var $freeProductID = 57;
/**
* constructor method
* 构造方法
* Attaches our class to the $_SESSION['cart'] class and watches for 2 notifier events.
*/
function freeProduct() {
$this->attach($this, array('NOTIFIER_CART_ADD_CART_END', 'NOTIFIER_CART_REMOVE_END'));
}
/**
* Update Method
*
* Called by observed class when any of our notifiable events occur
*
* @param object $class
* @param string $eventID
*/
function update(&$class, $eventID) {
if ($_SESSION['cart']->show_total() >= $this->freeAmount && !$_SESSION['cart']->in_cart($this->freeProductID) ) {
$_SESSION['cart']->add_cart($this->freeProductID);
}
if ($_SESSION['cart']->show_total() < $this->freeAmount && $_SESSION['cart']->in_cart($this->freeProductID) ) {
$_SESSION['cart']->remove($this->freeProductID);
}
if ($_SESSION['cart']->in_cart($this->freeProductID)) {
$_SESSION['cart']->contents[$this->freeProductID]['qty'] = 1;
}
}
}
?>

 

     当然,也许由于开发者也不可能考虑的很周全,有时候在代码中不一定在我们想要的地方都进行了事件通知。遇到这种情况,还是有可能对核心代码做少量修改的。但是通过使用观察者模式,还是可以尽量的避免修改其核心代码。

posted on 2010-03-15 16:11  东国先生  阅读(1673)  评论(0编辑  收藏  举报