DDD實戰:一段訂單建立程序-Part 2

我在DDD實戰:一段訂單建立程序-Part 1進行了一次效果不佳的重構。

最後不盡理想的結果如下:

orderRepository = new OrderRepository();
    }

    private function getNewOrderOrCreate()
    {
        if (Auth::check()){

            $order = $this->orderRepository->getNewOrderByUser(Auth::user());
            if ( !$order ){
                $order = Order::createWithUser(Auth::user());
            }
                        
        } else {
            
            $order = $this->orderRepository->getNewOrderBySesssionId(Session::getId());            
            if ( !$order ){
                $order = Order::createWithSession(Session::getId());
            }

        }
        
        return $order;
    }

    public function getOrder()
    {              
        $order = $this->orderRepository->getNewOrderOrCreate();

        return View::make('client/order', ['order' => $order]);
    }

}

我對controller中的getNewOrderOrCreate函式非常不滿意。
controller中的其他部份,都只是初始化某些類別、把某些參數傳來傳去,謹此而已,唯獨這個函式內含複雜邏輯。真醜。

但是那些判斷logic確實是controller該負責的事情,也不能丟進model,怎麼辦呢?

DDD觀點

DDD中區分了Application Layer、Domain Layer。乍看之下getNewOrderOrCreate不能進Domain Layer,只能硬放在Application Layer變成醜controller。

我在DDD實戰:一段金流程序提到過Service的概念。

我研究了一下發現…

其實Service又可分為Application Service、Domain Service以及Infrastructure Service。

要判斷一個Service隸屬於哪種,常常非常困難(譬如說,您覺得DDD實戰:一段金流程序中的ReceivePaymentNotification算是Application service還是Domain service?)

不過眼前的getNewOrderOrCreate卻非常清楚,應該是屬於Application Layer!

(但這都沒關係。目前我沒打算針對三種Service在程式中加上namespace,也沒打算在檔案結構上分別開資料夾之類的。現階段我就隨便開個Service資料夾,然後管他哪種Service通通丟進去就好了。)

那麼,就讓我來封裝一個Service,接著在Controller使用它吧:

getOrCreate();

        return View::make('client/order', ['order' => $order]);
    }

}
orderRepository = new OrderRepository();
    }
    
    public function getOrCreate()
    {
        if (Auth::check()){

            $order = $this->orderRepository->getNewOrderByUser(Auth::user());
            if ( !$order ){
                $order = Order::createWithUser(Auth::user());
            }
                        
        } else {
            
            $order = $this->orderRepository->getNewOrderBySesssionId(Session::getId());            
            if ( !$order ){
                $order = Order::createWithSession(Session::getId());
            }

        }
        
        return $order;
    }
        
}

終於成功了!終於讓controller內的code看起來非常簡潔、expressive,卻又不影響到Domain Layer!
我還發現,getNewOrderOrCreate光看函式名稱就覺得概念模糊。這種模糊感本身就暗示了抽象化的不足、程式設計想得不夠清楚。
一模一樣的內容,封裝成類別、再重新命名,就成了FetchOrderForClient底下的getOrCreate,真是清楚多了。