代码中经常遇到多个if else的情况 ,以前对多态理解只限于了解,并没有真正使用过。今天听老大讲了下,把自己的理解帖出来,一下代码均基于PHP实现,不态了解java的多态机制。
首先,我们以订单作为一个例子,操作一个订单的时候,基本上都要基于订单状态,做出相应操作。我们假设一个订单有一下几种状态:1,created(创建状态,等待工作人员审核),2,authed(审核通过,等待发货),3,shipped(已发货状态),4,completed(完成状态)。
当用户提交订单后,对订单的操作就有取消,审核,发货,完成等几个操作。假设要对订单进行取消操作,订单状态必须是created和authed状态。要对订单进行审核,订单状态必须是created,要发货,订单状态必须authed,要执行完成操作,订单必须是shipped状态, completed状态的订单,不能执行任何操作。
要执行这些操作,不用多态的情况下,我们的代码里会充斥着许多if else。如果业务逻辑再复杂些,代码中的if else条件会多得让你搞不清楚,或许你当时明白,但是过一两天你再来修改这段代码的时候,90%以上的情况你都需要花很长理一遍。如果是别人维护你的代码,再加上个人写代码的风格不同,别人就需要更长的时间来理解你的代码,这造成了维护成本过高的问题。
现在,假如我们做一个要对订单做一些操作,考虑先面代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| <?php
interface OrderService { public function cancelOrder($id); public function authOrder($id); public function shippingOrder($id); public function completeOrder($id); }
class OrderServiceImpl extends BaseService implements OrderService {
public function cancelOrder($id) { $order = $this->getOrder($id); if ($order['status'] != 'created' || $order['status'] != 'authed') throw $this->createServiceException('Can\'t cancel order(id=' . $id . ')'); return $this->getOrderDao()->update($id, array('status' => 'cancel'));
}
public function authOrder($id) { $order = $this->getOrder($id); if ($order['status'] != 'created') throw $this->createServiceException('Can\'t auth order(id=' . $id . ')'); return $this->getOrderDao()->update($id, array('status' => 'authed'));
}
public function shippingOrder($id) { $order = $this->getOrder($id); if ($order['status'] != 'authed') throw $this->createServiceException('Can\'t shipping order(id=' . $id . ')'); return $this->getOrderDao()->update($id, array('status' => 'shipped'));
}
public function completeOrder($id) { $order = $this->getOrder($id); if ($order['status'] != 'shipped') throw $this->createServiceException('Can\'t complete order(id=' . $id . ')'); return $this->getOrderDao()->update($id, array('status' => 'completed'));
}
public function getOrder($id) { $order = $this->getOrderDao()->findOrder($id); if (empty($order)) throw $this->createServiceException('Order does not exist(id=' . $id . ')'); return $order; }
}
|
以上代码中,除getOrder方法外,结构相似,而且都有if else结构,因为写法的原因else并没有体现出来,如果义务逻辑复杂,会有更多的if else,甚至是if(){} elseif(){} elseif(){}else{}这种复杂的判断语句出现。
现在我们开始使用多态。首先,订单有4个状态,created、authed、shipped和completed,依据这四个状态我们就可以抽象出四种类型的订单(就和人可以抽象成男人和女人一样),我们把依据四个状态抽象出来的订单叫做StatusOrder;现在我们定义一个接口:
1 2 3 4 5 6 7 8 9 10 11 12
| interface StatusOrder {
public function cancelOrder(); public function authOrder(); public function shippingOrder(); public function completeOrder();
}
|
现在我们来实现四种不状态的订单类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
| class BaseOrder {
private $order;
public function __construct($id) { $id = (int) $id; $order = $this->getOrderDao()->findOrder($id); if (empty($order)) throw new Exception('Order does not exist(id=' . $id . ')'); $this->order = $order; }
public function getOrder() { return $this->order; }
}
class CreatedOrder extends BaseOrder implements StatusOrder {
public function cancelOrder() { $order = $this->getOrder(); return $this->getOrderDao()->update($order['id'], array('status' => 'cancel')); }
public function authOrder() { $order = $this->getOrder(); return $this->getOrderDao()->update($id, array('status' => 'authed')); }
public function shippingOrder() { $order = $this->getOrder(); throw new Exception('Can\'t shipping order(id=' . $order['id'] . ')'); }
public function completeOrder($id) { $order = $this->getOrder(); throw new Exception('Can\'t complete order(id=' . $order['id'] . ')'); }
}
class AuthedOrder extends BaseOrder implements StatusOrder {
public function cancelOrder() { $order = $this->getOrder(); return $this->getOrderDao()->update($order['id'], array('status' => 'authed')); }
public function authOrder() { $order = $this->getOrder(); throw new Exception('Can\'t auth order(id=' . $order['id'] . ')'); }
public function shippingOrder() { $order = $this->getOrder(); return $this->getOrderDao()->update($order['id'], array('status' => 'shipped')); }
public function completeOrder() { $order = $this->getOrder(); throw new Exception('Can\'t complete order(id=' . $order['id'] . ')'); }
}
class ShippedOrder extends BaseOrder implements StatusOrder {
public function cancelOrder() { $order = $this->getOrder(); throw new Exception('Can\'t cancel order(id=' . $order['id'] . ')'); }
public function authOrder() { $order = $this->getOrder(); throw new Exception('Can\'t auth order(id=' . $order['id'] . ')'); }
public function shippingOrder() { $order = $this->getOrder(); throw new Exception('Can\'t shipping order(id=' . $order['id'] . ')'); }
public function completeOrder() { $order = $this->getOrder(); return $this->getOrderDao()->update($order['id'], array('status' => 'completed')); }
}
class CompleteOrder extends BaseOrder implements StatusOrder {
public function cancelOrder($id) { $order = $this->getOrder(); throw new Exception('Can\'t cancel order(id=' . $order['id'] . ')'); }
public function authOrder($id) { $order = $this->getOrder(); throw new Exception('Can\'t auth order(id=' . $order['id'] . ')'); }
public function shippingOrder($id) { $order = $this->getOrder(); throw new Exception('Can\'t shipping order(id=' . $order['id'] . ')'); }
public function completeOrder($id) { $order = $this->getOrder(); throw new Exception('Can\'t complete order(id=' . $order['id'] . ')'); }
}
|
现在,我们在Service层(业务逻辑层)去实现订单操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class OrderServiceImpl extends BaseService implements OrderService { private function getStatusOrder($id) { $order = $this->getOrderDao()->findOrder($id); $statusOrder = ucfirst(strtolower($order['status'])).Order; return new $statusOrder; }
public function cancelOrder($id) { return $this->getStatusOrder($id)->cancelOrder($id); }
public function authOrder($id) { return $this->getStatusOrder($id)->authOrder($id);
}
public function shippingOrder($id) { return $this->getStatusOrder($id)->shippingOrder($id); }
public function completeOrder($id) { return $this->getStatusOrder($id)->completeOrder($id); }
}
|
客户端调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| class OrderController {
public function cancelAction($id) { try { $this->getOrderService()->cancelOrder($id); return 'success'; } catch (Exception $e){ return $e->getMessage(); } }
public function shippingAction($id) { try { $this->getOrderService()->shippingOrder($id); return 'success'; } catch (Exception $e) { return $e->getMessage(); } }
}
|
使用多态以后,代码变的简洁,消除了相同形式的代码和if语句。service层(业务逻辑层)执行操作的时候不在关心订单所处的状态,不需要判断。同时,如果我们的订单还要加入一个状态,比如审核未通过(authFailed),这时可以对审核未通过的订单做一些操作,如果按照原来的写发,我们还要去考虑原有代码当中的if else语句,例如:要求要审核未通过(authFailed)也可以被取消, 原来写法中的代码:
1 2 3 4 5 6 7 8
| public function cancelOrder($id) { $order = $this->getOrder($id); if ($order['status'] != 'created' || $order['status'] != 'authed') throw $this->createServiceException('Can\'t cancel order(id=' . $id . ')'); return $this->getOrderDao()->update($id, array('status' => 'cancel'));
}
|
会变成:
1 2 3 4 5 6 7 8
| public function cancelOrder($id) { $order = $this->getOrder($id); if ($order['status'] != 'created' || $order['status'] != 'authed' || $order['status'] != 'authFailed') throw $this->createServiceException('Can\'t cancel order(id=' . $id . ')'); return $this->getOrderDao()->update($id, array('status' => 'cancel'));
}
|
如果其他操作也涉及到审核失败这个状态,那我们还要修改其他代码。
使用多态以后,我们添加一个类AuthFailed实现StatusOrder接口,其他代码基本不用修改,就可以实现功能增加,系统可维护性和可扩展性就大大提升。
以上代码均为伪代码