10
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

EC-CUBEで利用しているデザインパターン

Last updated at Posted at 2019-12-19

一見簡単そうに見えるカートシステムですが、EC-CUBEを実際に開発してみると、とても複雑な処理を実現しているのがわかります。
EC-CUBE4系では、とても複雑な処理を、できるかぎり汎用的にするため、様々なデザインパターンを使用しています。
そのうちの一部をご紹介します。

Chain of Responsibility パターン

エンティティの setter などで使用しています。
各メソッドをチェーンのようにつなげることができます。

        $Customer = new Customer();
        $Customer
            ->setName01($data['name01'])
            ->setName02($data['name02'])
            ->setKana01($data['kana01'])
            ->setKana02($data['kana02'])
            ->setCompanyName($data['company_name'])
            ->setEmail($data['email'])
            ->setPhonenumber($data['phone_number'])
            ->setPostalcode($data['postal_code'])
            ->setAddr01($data['addr01'])
            ->setAddr02($data['addr02']);

Decorator パターン

商品明細を簡単に扱うため、 \Doctrine\Common\Collections\ArrayCollection を拡張した OrderItemCollection で使用しています。

以下は商品の ProductClass の配列を取得する例です。
(filter メソッドを使ってもいいですが、わかりやすく foreach を使います...)


// OrderItemCollection を使用しない場合
$ProductOrderItem = [];
foreach ($Order->getOrderItems() as $OrderItem) {
    if ($OrderItem->isProduct()) {
        $ProductOrderItem[] = $OrderItem->getProductClass();
    }
}

// OrderItemCollection を使用
// Order::getOrderItems() で OrderItemCollection が返ってくる
$ProductOrderItem = $Order->getOrderItems()->getProductClasses()->toArray();

State パターン

購入フローの OrderStateMachine で使用しています。

ステートマシン図

  • OrderStateMachine::can() で、次のステータスに遷移可能かチェックし
  • OrderStateMachine::apply() で、注文ステータスを変更します。
$Order = ...;
$NextStatus = $orderStatusRepository->find(OrderStatus::PAID);
// ステータスを遷移させることができるかどうか
if ($orderStateMachine->can($Order, $NextStatus)) {
    // ステータスの遷移
    $orderStateMachine->apply($Order, $NextStatus);
}

例えば、出荷完了後の返品は、在庫を戻さない といった処理を実現しています。

Strategy パターン

PurchaseFlow で使用しています。
カート、購入フロー、注文管理画面で共通して必要な要件は、 商品の明細を集計して、合計金額を算出する ことです。
しかし、それぞれ商品の状態が異なります。

  • カート

    • 商品の内容、数量は未確定
    • 在庫は確保されていない
    • 送料・手数料は計算しない
  • 購入フロー

    • 商品の内容、数量は確定している
    • 在庫は確保されていない
    • 送料・手数料を計算する
    • ポイントを計算する(加算しない・使用する)
  • 注文管理画面

    • 商品は購入済み
    • 在庫を確保済み
    • 送料・手数料を計算する
    • ポイントを計算する(ステータスによっては加算済み・使用する)

共通する処理もありますが、それぞれ処理の流れが異なったり、独自の処理が必要になったりします。

PurchaseFlow では、ItemProcessor や ItemValidator など処理を Strategy クラスとし、 Context である PurchaseFlow クラスで実行しています。
どのような Strategy を組み合わせるかは、 purchaseflow.yaml に定義しています。

この Strategy パターンの良いところは、プラグインなどで Strategy を作成して、独自の処理を簡単に追加できることです。
処理の順番を変えたい場合も、 purchaseflow.yaml を変更するだけでできます。
また、 Strategy クラス一つ一つは、小さくシンプルなプログラムですので、単体テストも簡単に作成できます。

このように、小さな処理をするクラスを組み合わせて、様々なアルゴリズムに対応するのが Strategy パターンです。
文章だけだと大変わかりづらいですが、 PurchaseFlow をツリー表示 するメソッドをコールすると、ちょっとイメージしやすくなると思います。

例えば、購入フローを処理する shopping Flow はこんな感じ

├ shopping flow
ItemValidator
│├ Eccube\Service\PurchaseFlow\Processor\DeliverySettingValidator
│├ Eccube\Service\PurchaseFlow\Processor\ProductStatusValidator
│└ Eccube\Service\PurchaseFlow\Processor\PriceChangeValidator
ItemHolderValidator
│├ Eccube\Service\PurchaseFlow\Processor\StockMultipleValidator
│├ Eccube\Service\PurchaseFlow\Processor\SaleLimitMultipleValidator
│├ Eccube\Service\PurchaseFlow\Processor\EmptyItemsValidator
│└ Plugin\Coupon4\Service\PurchaseFlow\Processor\CouponProcessor
ItemPreprocessor
ItemHolderPreprocessor
│├ Eccube\Service\PurchaseFlow\Processor\TaxProcessor
│├ Eccube\Service\PurchaseFlow\Processor\OrderNoProcessor
│├ Eccube\Service\PurchaseFlow\Processor\DeliveryFeePreprocessor
│├ Eccube\Service\PurchaseFlow\Processor\DeliveryFeeFreeByShippingPreprocessor
│├ Eccube\Service\PurchaseFlow\Processor\PaymentChargePreprocessor
│├ Eccube\Service\PurchaseFlow\Processor\TaxProcessor
│└ Plugin\Coupon4\Service\PurchaseFlow\Processor\CouponProcessor
DiscountProcessor
│└ Eccube\Service\PurchaseFlow\Processor\PointProcessor
ItemHolderPostValidator
 ├ Eccube\Service\PurchaseFlow\Processor\AddPointProcessor
 ├ Eccube\Service\PurchaseFlow\Processor\PaymentTotalLimitValidator
 ├ Eccube\Service\PurchaseFlow\Processor\PaymentTotalNegativeValidator
 ├ Eccube\Service\PurchaseFlow\Processor\PaymentChargeChangeValidator
 └ Eccube\Service\PurchaseFlow\Processor\DeliveryFeeChangeValidator

しかし現在のバージョンでは、処理の流れが見えづらいのは否めず、ステップ実行を駆使しないと開発が難しくなってしまったのが難点ですね。。。

10
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?