代码中经常遇到多个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);
//根据数据库字段获取类名,若取出的订单状态为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);
}

}

客户端调用:

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)
{
//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)也可以被取消, 原来写法中的代码:

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接口,其他代码基本不用修改,就可以实现功能增加,系统可维护性和可扩展性就大大提升。

以上代码均为伪代码