2017-10-07 57 views
0

爲了將我們的邏輯從數據庫遷移到微服務,我在幾個月前修改了可用性引擎。當時,業務邏輯是相當簡單:如何確定組合房間的可用性DDD

  • 資源(會議室,桌子,空蕩蕩的辦公室,設備)僅當它是不是已經預訂給定的時間框架(即:無其他使用相同的資源)

  • 當資源是不可用的,最接近的可用時間框架必須被計算

爲了滿足這些要求訂票,我建立了小片的下面的代碼:

public class Schedule : IAggregateRoot 
{ 
    public int CityId { get; } 
    public int BuildingId { get; } 
    public int CentreId { get; } 
    public int ResourceId { get; } 

    public ICollection<Booking> Bookings { get; } 

    public Schedule(int cityId, int buildingId, int centreId, int resourceId, IEnumerable<Booking> bookings) 
    { 
     CityId = cityId; 
     BuildingId = buildingId; 
     CentreId = centreId; 
     ResourceId = resourceId; 
     Bookings = new List<Booking>(bookings); 
    } 

    public bool IsTimeSlotFree(DateTimeOffset startDate, DateTimeOffset endDate) 
     => Bookings.Any(/* Predicate */); 

    public IEnumerable<Availability> GetFreeTimeSlots(
     DateTimeOffset startDate, 
     DateTimeOffset endDate, 
     TimeSpan duration) 
    { 
     var nbSlots = Math.Floor((endDate - startDate)/duration); 
     for(int i=0; i<nbSlots; i++) { 
      /* yield return availability */ 
     } 
    } 
} 

public class Availability : ValueObject 
{ 
    public DateTimeOffset StartDate { get; set; } 
    public DateTimeOffset EndDate { get; set; } 
    public int ResourceId { get; set; } 
    public bool IsAvailable { get; set; } 
} 

public class Resource : Entity 
{ 
    public string Code { get; set; } 

    // Required for EF Core 
    protected Resource() { } 
} 

public class Booking : Entity 
{ 
    public DateTimeOffset StartDate { get; set; } 
    public DateTimeOffset EndDate { get; set; } 
    public string Status { get; set; } 
    public int ResourceId { get; set; } 

    // Required for EF Core 
    protected Booking() { } 
} 

幾周前,我被要求處理組合房間(兩個較小的房間可以合併成一個更大的組合房間)。在這種情況下,組合房間只能使用其子房間和本身。換句話說,我需要檢查幾個時間表來確定可用性,不幸的是,我當前的抽象級別不允許(一個時間表,一個房間)。

我發現的唯一方法是檢索資源及其子(= subrooms),然後創建一個包含ResourceId和預訂字典的計劃。

public class Resource : Entity 
{ 
    public string Code { get; set; } 

    public Resource Parent { get; set; } 
    public ICollection<Resource> Children { get; set; } 

    // Required for EF Core 
    protected Resource() { } 
} 

public class Schedule : IAggregateRoot 
{ 
    public int CityId { get; } 
    public int BuildingId { get; } 
    public int CentreId { get; } 
    public int ResourceId { get; } 

    public IDictionnary<int, ICollection<Bookings>> Bookings 

    (...) 
} 

我不覺得這個解決方案真的很優雅。對我來說,更好的解決方案是檢索計劃並將它們合併以確定實際可用性。我嘗試了幾種解決方案,但最終我寫了意大利麪代碼。

對於如何重新設計我的聚合以正確處理這個新概念,您有什麼想法嗎?

謝謝 勒布

+0

有沒有提前知道有限的子房可能性,還是可以將任何兩個房間組合成一個更大的房間? – guillaume31

+0

是的,他們提前知道。我知道哪些房間可以合併。其實我把這個信息存儲在一個分貝:) – Seb

回答

1

在猜測,核心的問題是,你缺少域概念模型。

我的猜測是,您遺漏了描述可用庫存的產品目錄的表示。在該目錄中,您將獲得101號房間入口和102號房間入口。如果這些房間可以打包在一起,那麼您還可以輸入包裹[#101和#102]。

因此,軟件包的可用性很容易 - 將軟件包中元素的時間表交叉。既然你知道包的內容,很容易找到你需要調和的時間表。

請注意,您可以更新目錄 - 添加或刪除軟件包 - 不以任何方式影響預訂。

你當然必須弄清楚你將如何處理多個房間的實際預訂。有幾種可能性;最簡單的一個,我猜想你的用戶最熟悉的是允許計劃彙總接受重疊預訂,設置一個雙重預訂標誌來跟蹤需要採取補償行動的情況。

另一種選擇是使用saga模式預訂軟件包;如果無法預訂整個包裹,則執行預訂編排的過程知道取消預訂房間。

您可以通過將所有日程表移動到單個聚合中來簡化操作;將一致性邊界擴大到更大規模(可能屬性,而不是單個房間);這剝奪了較大房間的自主性和規模。

+0

謝謝你這個有用的答案。我將修改我的模型以添加這個包的概念。如果我理解正確,你可以得到一個包的時間表,而不是單個資源。我對麼?此外,可用性引擎還處於「微服務」狀態,不知道如何取消/預訂。它只用於實際獲得資源的可用性。 – Seb

0

幾乎任何包含資源調度的域模型都將Day的概念視爲單獨的聚合。沒有它,你將永遠保持聚合。不同的上下文可以保持一天中的不同表現:

  • 預訂可以有房類型和可用性
  • 定價可以有房型和價格
  • 接待可以有房分配,抵港及離港