设计模式:外观模式
当涉及到设计模式时,你可能会问:
为什么在编程中需要使用设计模式?
我们的代码不用设计模式也能正常工作。
为此,我想反问:“你愿意住在一个豪华的家,还是一个只是简单的四面墙的地方?”毕竟,无论哪种,都可以满足我们的需求。
一般情况下,我们会选择一个豪华的家,因为它提供了更好的设施,需要更少的维护,保养也不用那么麻烦,因为基础架构已经存在。
同样的道理也适用于编程:采用设计模式的代码是很容易理解,易于维护,易于扩展的。
在这系列的教程中,我们将覆盖一些对我们在编程中非常有用的设计模式。你讲了解它们的优点和缺点,以及在什么情况下去使用它们。
在这系列的教程中,我将使用PHP语言来说明设计模式;但是设计模式实际上是一个可以应用到任何编程语言中的概念。它只是根据你选择的语言,改变相关的语法而已。
设计规则将分为下面四个分类:
-
创建模式
-
结构模式
-
行为模式
-
并行模式
在这篇文章中,我们将了解外观模式。它属于结构模式的范畴,因为它处理的是如何使你的代码的结构易于理解和长期保持良好的可维护性。
外观模式
UML
问题
让我们假设,你需要按顺序执行一些操作,在你应用中的多个地方都会请求同样的动作。你必须一遍一遍地把相同的代码拷贝到不同的地方。你完成了这些操作后,但是过了一段时间,你发现在这段代码中需要修改一些东西。
你发现问题的所在了吗?我们需要在所有出现这段代码的地方都一一进行修改。这非常痛苦,不是吗?
解决方案
作为一种解决方案,你应该做的是创造一个主控制器,它处理所有的重复代码。在需要调用这段代码的地方,我们将只需提供所需的参数给这个主控制器,让它来完成操作。
现在,如果我们需要修改一些东西,那我们只需要修改这个主控制器里面的代码,而不需要在所有使用这段过程的地方修改。
例子
在本文中,我们使用简单的例子来说明问题。假设你被赋予了规划你朋友婚礼的任务。如果你自己一个人做所有事情,想象一下你需要搞定的东西。这将导致很高的错误率发生,忽略了某些可能极大地影响你朋友婚礼的东西。
这种情况下,你需要一个婚礼策划者,来确保所有的工作都得到良好的管理,很少出错。
这里,你作为一个客户端来启动这个过程,然后这个婚礼策划师作为你的一个“门面”,根据你的方向来完成工作。
代码例子
这里,我们将看到多个例子,这些对于网页来说都是非常平常的例子。我们将看到外观设计模式产品结账过程中的实现,但是在看到完美的代码之前,让我们先看看有问题的代码。
一个简单的结账过程由下面的步骤组成:
-
添加产品到购物车。
-
计算运费
-
计算折扣
-
生成订单
问题:
// Simple CheckOut Process
$productID = $_GET['productId'];
$qtyCheck = new productQty();
if($qtyCheck->checkQty($productID) > 0) {
// Add Product to Cart
$addToCart = new addToCart($productID);
// Calculate Shipping Charge
$shipping = new shippingCharge();
$shipping->updateCharge();
// Calculate Discount Based on
$discount = new discount();
$discount->applyDiscount();
$order = new order();
$order->generateOrder();
}
在上面的代码中,你将发现这个结账过程包括了多个需要被生成的对象来完成整个结账操作。想象一下你需要在多个地方实现这个过程。如果是这样的话,当这些代码需要修改时将会是一个问题。最后是把这个过程统一放到一个地方。
解决方法
我们将使用外观模式来实现之前的操作,使得代码更易管理和扩展。
class productOrderFacade {
public $productID = '';
public function __construct($pID) {
$this->productID = $pID;
}
public function generateOrder() {
if($this->qtyCheck() > 0) {
// Add Product to Cart
$this->addToCart();
// Calculate Shipping Charge
$this->calulateShipping();
// Calculate Discount if any
$this->applyDiscount();
// Place and confirm Order
$this->placeOrder();
}
}
private function addToCart () {
/* .. add product to cart .. */
}
private function qtyCheck() {
$qty = 'get product quantity from database';
if($qty > 0) {
return true;
} else {
return true;
}
}
private function calulateShipping() {
$shipping = new shippingCharge();
$shipping->calculateCharge();
}
private function applyDiscount() {
$discount = new discount();
$discount->applyDiscount();
}
private function placeOrder() {
$order = new order();
$order->generateOrder();
}
}
现在,我们创建了产品订单的一个外观,我们所需要做的,就像下面这样调用:
// Note: We should not use direct get values for Database queries to prevent SQL injection
$productID = $_GET['productId'];
// Just 2 lines of code in all places, instead of a lengthy process everywhere
$order = new productOrderFacade($productID);
$order->generateOrder();
现在,想象一下,当你需要修改这个订单流程的代码时,只需要在外观中修改即可。
总结
简单地说,外观模式就是把一系列的操作封装到一个统一的接口下。