1

私はこれに非常に似たデザインを持っています:

ここに画像の説明を入力してください

ここで、 NewOrderRegisteredGrantedはすべて共通のメソッドAddOrderline()とを持っているCancel()ため、両方のメソッドを親クラスにリファクタリングするのは簡単です。

Cancelこの問題は、線を引きたいときに発生しますShipped(現在は図には示されていません)。

Shipped lineはサポートしていないので、NewOrderRegisteredGrantedAddOrderline()の親クラスを2つのクラスに分割する必要があります。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メソッドの1つが返すものと一致する、状態の文字列名を返すだけです。

この方法では、モックとテストを簡単に行うこともできます(これは、あらゆるアプリケーションにとって重要ですが、特に、人々のお金や製品を扱っているeコマースでは重要です)。

于 2013-02-11T14:23:55.300 に答える