changed 2 years ago
Linked with GitHub

Domain-Driven Design

Domain Model ~= Businss Model aka Business Logic

Type State Method
Entity/Aggregate/Value Yes Yes
Service No Yes
  • Aggregate -> ID (Unique)
    • Boundary ~= Module -(組成)> System
    • Aggreate ~= Moudle ===> 找 Aggregate Root == 找邊界
    • State
      • Order -> sub-total
      • OrderItems -> [OrderItem<id: 1>]
    • Method
      • Change State
      • Change Aggregated Entity State -> order.update_amount(product_id, amount)
        • items.select { |i| i.pid == product_id }.update_amount(amount)
    • When Save, all aggregate entities are saved
      • has_many :items autosave: true
  • Entity -> ID (Unique)
    • State
      • OrderItem -> unit_price
    • Method
      • update_amount() => self.amount = amount
  • Value Object -> No ID -> Not Unique
    • Immutable
    • Money -> Composite([100, TWD])
  • Service Object
    • Order 想 update_amount 時,商品數量必須足夠 <== 條件
    • OrderItemAmountUpdater ->
      • Service 協調
      • prodsuct.stock_available?(amount)
      • order.update_amount(product.id, amount)
# Product (Context) # * Context - Store Manager # * Context - Customer class Money attr_reader :value, :currency def initialize(value, currency) @value = value @currency = currency end def +(other) # check currency new(value + other.value, currency) end end module Store class Product belongs_to :store compose_of :price, class_name: 'Money', mapping: [%i(price value), %i(currency currency)] end end class Order # ---> product.xxxx # product_id (Value != Association) --> Link # product_name # product_unit_price end

Flow

-> View
-> Controller User Flow
-> A Case -> Reseller -> No stock check
-> B Case -> Customer -> Check stock
-> Model Business Logic

class CheckoutController def create # Step 1 cart.items.each do |item| # ... check item.product_id end # Step 2 Order.create_from(cart) # 拆 Service Object end end # ... class CheckoutController rescue_from ...., :on_product_not_available # .... def create # Step 1 ProductAvailableService.new.call(cart) # raise Error # Step 2 @order = BuildOrderService.new.call(cart) @order.save! # render end end class Reseller::CheckoutController rescue_from ...., :on_product_not_available # .... def create # Step 1 # ProductAvailableService.new.call(cart) # raise Error # Step 2 @order = BuildOrderService.new.call(cart) @order.save! # render end end
Select a repo