我的设计与此非常相似:
此处 NewOrder ,已注册& 授予都具有常用方法AddOrderline()
和Cancel()
,因此将这两种方法重构为父类很容易。
如果我想Cancel
Shipped
行(目前图中未显示),则会出现问题。
由于已发货行不支持AddOrderline()
,因此我需要打破 NewOrder 的父类,已注册& 授予分为Cancel()
的2个一级和AddOrderline()
的另一个。
现在NewOrder
必须扩展2个父类才能获得2个函数。
备注
答案 0 :(得分:0)
我会考虑将接口与实现分开。例如在Java中
interface Cancellable {
void cancel();
}
interface Shippable{
void ship();
}
等
public class NewState implements Cancellable, Shippable {
public void cancel() { ... }
public void ship() { ... }
}
如果您有基础私有状态,它可以实现所有所需的接口,并且您的公共状态只需要委派这些受支持的状态。 e.g。
public class UnderlyingState implements Cancellable, Shippable ... {
public void cancel() { ... }
public void ship() { ... }
}
public class ShippableState implements Shippable {
private UnderlyingState ustate = new UnderlyingState();
public void cancel() {
// you can *only* cancel this
ustate.cancel();
}
}
在上面你可能需要返回一个新的状态对象(而不是void
)并让你的Order
采用那个新的状态。 UnderlyingState
对象将强制执行某个状态机。
令人头疼的是,随着状态数量的增加,接口和实现也会增加。
答案 1 :(得分:-1)
首先,您需要一个状态管理器来处理状态:
<?php
class StateManager
{
protected $states = array();
public function registerState(StateInterface $state)
{
$this->states[$state->getName()] = $state;
}
public function getState($state)
{
if (!array_key_exists($state, $this->states)) {
throw new InvalidArgumentException();
}
return $this->states[$state];
}
}
然后你有一个可以对订单执行操作的订单管理器:
<?php
class OrderManager
{
protected $stateManager;
public function ship(OrderInterface $order)
{
try {
$this->stateManager->getState($order->getState())->ship($order);
} catch (OperationNotAllowedException $exception) {
// However you want to handle the fact that the state can't be shipped
}
}
}
如果订单无法在某种状态下执行操作,则会抛出异常:
<?php
class OperationNotAllowedException extends Exception
{
}
州的界面:
<?php
interface StateInterface
{
public function getName();
// Then your normal functions
public function ship(OrderInterface $order);
public function cancel(OrderInterface $cancel);
public function addOrderLine(OrderInterface $order);
public function refund(OrderInterface $order);
}
现在,当您设置应用程序时:
$newOrderState = new NewState($database, $otherdependencies);
$stateManager->registerState($newOrderState);
您的订单对象只返回其所处状态的字符串名称,该状态与状态getName
方法返回的状态相匹配。
此方法还允许轻松进行模拟和测试(这对于任何应用程序都很重要,尤其是您处理人员资金和产品的电子商务)。