通过重写机制和自动加载机制, 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; } } } ?>
当然,也许由于开发者也不可能考虑的很周全,有时候在代码中不一定在我们想要的地方都进行了事件通知。遇到这种情况,还是有可能对核心代码做少量修改的。但是通过使用观察者模式,还是可以尽量的避免修改其核心代码。 (责任编辑:好模板) |