在State Pattern中实现继承层次结构

时间:2013-02-11 14:17:15

标签: c# java php design-patterns

我的设计与此非常相似:

enter image description here

此处 NewOrder 已注册& 授予都具有常用方法AddOrderline()Cancel(),因此将这两种方法重构为父类很容易。

如果我想Cancel Shipped行(目前图中未显示),则会出现问题。

由于已发货行不支持AddOrderline(),因此我需要打破 NewOrder 的父类,已注册& 授予分为Cancel()的2个一级和AddOrderline()的另一个。

现在NewOrder必须扩展2个父类才能获得2个函数。

备注

  1. 此示例非常简化。我的真实应用程序有大约12个州。
  2. 代码是用PHP编写的,但C#或Java中的解决方案很受欢迎,因为我认为解决方案类似,因为它们都不支持多重继承。

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方法返回的状态相匹配。

此方法还允许轻松进行模拟和测试(这对于任何应用程序都很重要,尤其是您处理人员资金和产品的电子商务)。