代码中经常遇到多个if else的情况 ,以前对多态理解只限于了解,并没有真正使用过。今天听老大讲了下,把自己的理解帖出来,一下代码均基于PHP实现,不态了解java的多态机制。
首先,我们以订单作为一个例子,操作一个订单的时候,基本上都要基于订单状态,做出相应操作。我们假设一个订单有一下几种状态:1,created(创建状态,等待工作人员审核),2,authed(审核通过,等待发货),3,shipped(已发货状态),4,completed(完成状态)。
当用户提交订单后,对订单的操作就有取消,审核,发货,完成等几个操作。假设要对订单进行取消操作,订单状态必须是created和authed状态。要对订单进行审核,订单状态必须是created,要发货,订单状态必须authed,要执行完成操作,订单必须是shipped状态, completed状态的订单,不能执行任何操作。
要执行这些操作,不用多态的情况下,我们的代码里会充斥着许多if else。如果业务逻辑再复杂些,代码中的if else条件会多得让你搞不清楚,或许你当时明白,但是过一两天你再来修改这段代码的时候,90%以上的情况你都需要花很长理一遍。如果是别人维护你的代码,再加上个人写代码的风格不同,别人就需要更长的时间来理解你的代码,这造成了维护成本过高的问题。
现在,假如我们做一个要对订单做一些操作,考虑先面代码:
<!-- lang: php -->
<?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;现在我们定义一个接口:
interface StatusOrder {
//取消订单
public function cancelOrder();
//订单审核
public function authOrder();
//订单发货
public function shippingOrder();
//完成订单
public function completeOrder();
}
现在我们来实现四种不状态的订单类:
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层(业务逻辑层)去实现订单操作:
class OrderServiceImpl extends BaseService implements OrderService
{
// 获取某个状态订单类的一个实例,也可以使用一个工厂方法获取
private function getStatusOrder($id)
{
$order = $this->getOrderDao()->findOrder($id);
//根据数据库字段获取类名,若取出的订单状态为created, 则$statusOrder值为CreatedOrder
$statusOrder = ucfirst(strtolower($order['status'])).Order;
return new $statusOrder;
}
public function cancelOrder($id)
{
//TODO:权限检查
return $this->getStatusOrder($id)->cancelOrder($id);
}
public function authOrder($id)
{
//TODO:权限检查
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);
}
}
//客户端调用
class OrderController {
//取消订单
public function cancelAction($id)
{
//Other operation etc.
try {
$this->getOrderService()->cancelOrder($id);
return 'success';
} catch (Exception $e){
return $e->getMessage();
}
}
public function shippingAction($id)
{
//Other operation etc.
try {
$this->getOrderService()->shippingOrder($id);
return 'success';
} catch (Exception $e) {
return $e->getMessage();
}
}
// etc. ...........................................
}
使用多态以后,代码变的简洁,消除了相同形式的代码和if语句。service层(业务逻辑层)执行操作的时候不在关心订单所处的状态,不需要判断。同时,如果我们的订单还要加入一个状态,比如审核未通过(authFailed),这时可以对审核未通过的订单做一些操作,如果按照原来的写发,我们还要去考虑原有代码当中的if else语句,例如:要求要审核未通过(authFailed)也可以被取消, 原来写法中的代码:
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 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接口,其他代码基本不用修改,就可以实现功能增加,系统可维护性和可扩展性就大大提升。