1

我有一个与此非常相似的设计:

在此处输入图像描述

这里NewOrderRegisteredGranted都具有通用方法AddOrderline()and Cancel(),因此将这两种方法重构为父类很容易。

当我想要Cancel一条Shipped线时出现问题(目前图中未显示)。

由于Shipped行不支持AddOrderline(),因此我需要将NewOrderRegistered & Granted的父类分为 2 个类,一个用于 the Cancel(),另一个用于AddOrderline().

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

笔记

  1. 这个例子非常简化。我的真实应用程序有大约 12 个状态。
  2. 代码是用 PHP 编写的,但欢迎使用 C# 或 Java 的解决方案,因为我认为解决方案将是相似的,因为它们都不支持多重继承。
4

2 回答 2

0

我会考虑将接口与实现分离。例如在Java中

interface Cancellable {
   void cancel();
}
interface Shippable{
   void ship();
}

等等

public class NewState implements Cancellable, Shippable {
  public void cancel() { ... }
  public void ship() { ... }
}

如果你有一个底层的私有状态,它可以实现所有需要的接口,而你的公共状态只需要委托那些支持的状态。例如

 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对象将强制执行某些状态机。

令人头疼的是,随着您的状态数量增加,您的接口和实现也会增加。

于 2013-02-11T14:19:38.293 回答
-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方法之一返回的名称相匹配。

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

于 2013-02-11T14:23:55.300 回答