简体   繁体   English

在状态模式中实现继承层次结构

[英]Implementing the inheritance hierarchy in the State Pattern

I have a design which is very similar to this:我有一个与此非常相似的设计:

在此处输入图片说明

Here NewOrder , Registered & Granted all have the common methods AddOrderline() and Cancel() , so refactoring both methods to a parent class is easy.这里NewOrderRegisteredGranted都有公共方法AddOrderline()Cancel() ,因此将这两种方法重构为父类很容易。

The problem occurs when I want to Cancel a Shipped line (currently not shown in the figure).当我想CancelShipped行(当前未在图中显示)时会出现问题。

Since a Shipped line doesn't support AddOrderline() then I'll need to break the parent class for NewOrder , Registered & Granted into 2 class one for the Cancel() and another for AddOrderline() .由于Shipped线路不支持AddOrderline()因此我需要将NewOrderRegistered & Granted的父类分解为Cancel()AddOrderline()

Now NewOrder must extend 2 parent class to get the 2 functions.现在NewOrder必须扩展 2 个父类才能获得 2 个函数。

Notes笔记

  1. This example is very simplified.这个例子非常简化。 My real application has about 12 states.我的实际应用程序大约有 12 个状态。
  2. The code is in PHP, but solutions in C# or Java are welcomed because I presume that the solution will be similar as they all don't support multiple inheritance.代码使用 PHP,但欢迎使用 C# 或 Java 解决方案,因为我认为该解决方案将相似,因为它们都不支持多重继承。

I would consider the separation of the interface from the implementation.我会考虑将接口与实现分离。 eg in Java例如在 Java 中

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

etc.等等。

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

If you have an underlying private State, it can implement all the required interfaces, and your public States need only delegate those supported states.如果你有一个底层的私有状态,它可以实现所有需要的接口,而你的公共状态只需要委托那些支持的状态。 eg例如

 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();    
     }
   }

In the above you'd probably need to return a new state object (rather than void ) and have your Order adopt that new state.在上面,您可能需要返回一个新的状态对象(而不是void )并让您的Order采用该新状态。 The UnderlyingState object would enforce some state machine. UnderlyingState对象将强制执行某种状态机。

The headache with this is that as your number of states increase, your interfaces and implementation increases too.令人头疼的是,随着状态数量的增加,您的接口和实现也会增加。

First, you'll need a state manager to handle states:首先,您需要一个状态管理器来处理状态:

<?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];
    }
}

Then you have an order manager that can perform actions against orders:然后你有一个订单管理器,可以对订单执行操作:

<?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
        }
    }
}

An exception that gets thrown if an order can't take an action in a certain state:如果订单在特定状态下无法执行操作,则会引发异常:

<?php
class OperationNotAllowedException extends Exception
{
}

The interface for a state:状态接口:

<?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);
}

Now, when you setup your application:现在,当您设置应用程序时:

$newOrderState = new NewState($database, $otherdependencies);
$stateManager->registerState($newOrderState);

Your order object simply returns a string name for the state it's in, that matches what one of the state's getName methods returns.您的订单对象仅返回其所在状态的字符串名称,该名称与该状态的getName方法之一返回的内容相匹配。

This method also allows for easy mocking and testing (which is important for any application, but especially e-commerce where you are handling people's money and products).这种方法还允许轻松模拟和测试(这对于任何应用程序都很重要,尤其是在处理人们的金钱和产品的电子商务)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM