關於DDD的主要問題是將焦點放在域中,這就是爲什麼它稱爲Domain Driven設計。
當您開始詢問關係,聚合和實體時,甚至沒有深入探究包含域的內容,您實際上是在尋找數據庫建模而不是域。
請問,我不是說你在問錯誤的問題,也不是在批評他們,我認爲你在學習的過程中嘗試付諸實踐並沒有錯。
我不是DDD專家,我和你一樣學習,但我會盡力幫忙。
從思考什麼情況可能會出現關於Holydays管理開始。當你有不同的規則時,你可以從策略開始(我說的是最終的解決方案)。
建立一個好的和有意義的域名是非常困難的(至少對我而言)。你寫代碼。測試它。有洞察力,拋出你的代碼並重寫它。重構它。在軟件的生命週期中,你應該把重點放在域上,所以你應該一直在改進它。
開始編碼(如域的草稿),看看它是怎樣的。讓我們鍛鍊它。首先,爲什麼我們需要管理這些東西?我們試圖解決什麼問題?啊,有時候員工會問一些休息日,我們想控制它。我們可能會批准或不批准,這取決於他們希望「holyday」的原因,我們的團隊狀態如何。如果我們拒絕,他們仍然回家,我們會遲到決定我們是否打工或打工。執法無處不在的語言,讓我們在代碼中表達這個問題:
public interface IHolydayStrategy
{
bool CanTakeDaysOff(HolydayRequest request);
}
public class TakeCareOfChildren : IHolydayStrategy
{
public bool CanTakeDaysOff(HolydayRequest request)
{
return IsTotalDaysRequestedUnderLimit(request.Range.TotalDays());
}
public bool IsTotalDaysRequestedUnderLimit(int totalDays)
{
return totalDays < 3;
}
}
public class InjuredEmployee : IHolydayStrategy
{
public bool CanTakeDaysOff(HolydayRequest request)
{
return true;
}
}
public class NeedsToRelax : IHolydayStrategy
{
public bool CanTakeDaysOff(HolydayRequest request)
{
return IsCurrentPercentageOfWorkingEmployeesAcceptable(request.TeamRealSize, request.WorkingEmployees)
|| AreProjectsWithinDeadline(request.Projects);
}
private bool AreProjectsWithinDeadline(IEnumerable<Project> projects)
{
return !projects.Any(p => p.IsDeadlineExceeded());
}
private bool IsCurrentPercentageOfWorkingEmployeesAcceptable(int teamRealSize, int workingEmployees)
{
return workingEmployees/teamRealSize > 0.7d;
}
}
public class Project
{
public bool IsDeadlineExceeded()
{
throw new NotImplementedException();
}
}
public class DateRange
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
public int TotalDays()
{
return End.Subtract(Start).Days;
}
public bool IsBetween(DateTime date)
{
return date > Start && date < End;
}
}
public enum HolydayTypes
{
TakeCareOfChildren,
NeedToRelax,
BankOfHours,
Injured,
NeedToVisitDoctor,
WannaVisitDisney
}
public class HolydayRequest
{
public IEnumerable<Project> Projects { get; internal set; }
public DateRange Range { get; set; }
public HolydayTypes Reason { get; set; }
public int TeamRealSize { get; internal set; }
public int WorkingEmployees { get; internal set; }
}
下面是我很快寫了這個:
- Holydays可授予與否,視情況而定,並 原因,讓我們創建一個
IHolydayStrategy
。
- 創建一個空的(無產階級)
HolydayRequest
類。
- 對於每個可能的原因,讓我們創建一個不同的策略。
- 如果原因是要照顧孩子,他們可以休息幾天,如果 總的天數要求是在限制之下。
- 如果原因是因爲員工受傷,除了允許請求外,我們沒有 選擇。
- 如果原因是因爲他們需要放鬆,我們檢查我們是否有 可接受的工作僱員百分比,或者是否在 截止日期之內。
- 只要我在戰略中需要一些數據,我就使用
CTRL + .
到 自動創建HolydayRequest
中的屬性。
看看我怎麼不知道這些東西是如何存儲/映射的?我只是編寫代碼來解決問題,並獲取解決問題所需的信息。
顯然這不是最終的領域,只是一個草案。如果需要,我可能會拿走這段代碼並重寫,但現在還沒有感覺。
人們可能認爲這是沒用的,創建一個InjuredEmployee
班只是始終返回true,但這裏的關鍵是要利用通用語言的,把事情的明確越好,任何人都會閱讀和理解同樣的事情:「好吧,如果我們有一名受傷員工,他們總是可以休息幾天,不管團隊情況以及他們需要多少天。」「。 DDD解決這個概念時遇到的問題之一是開發人員,產品所有者,領域專家和其他參與者之間對術語和規則的誤解。
之後,我會開始用模擬數據編寫一些測試。我可能會重構代碼。
這 「3」:
public bool IsTotalDaysRequestedUnderLimit(int totalDays)
{
return totalDays < 3;
}
而這個 「0.7D」:
private bool IsCurrentPercentageOfWorkingEmployeesAcceptable(int teamRealSize, int workingEmployees)
{
return workingEmployees/teamRealSize > 0.7d;
}
的規格,在我看來,這不應該存在於一個戰略點。我們可能會應用規範模式來解耦。
當我們通過測試得到合理的初始解決方案後,現在讓我們考慮應該如何存儲它。我們可以在這裏使用最終定義的類(比如Team,Project,Employee)來映射ORM。
只要你開始寫你的域,關係將出現你的實體之間,這就是爲什麼我通常不關心所有的ORM將如何堅持我的域名,什麼是在這一點上聚集。
看看我還沒有創建一個Employee類,儘管這聽起來很重要。這就是爲什麼我們不應該從創建實體及其屬性開始,因爲它與創建表和字段完全相同。
你的DDD變成數據庫驅動設計那樣,我們不想這樣。當然,最終我們會成爲員工,但讓我們一步一步,只在需要時才創建。不要試圖立即開始建模,預測所有您需要的實體。把重點放在你的問題上,以及如何解決它。
關於你的問題,什麼是實體和什麼是聚合,我認爲你不是問他們的定義,而是考慮你的域名是否被認爲是一個或另一個。只要您的域名開始被您的代碼揭示,您最終會回答自己。當你開始開發你的應用程序層時,你應該知道它,它應該負責加載數據並委託給你的域。我的域名邏輯預期哪些數據,從哪裏開始查詢。
我希望我幫了別人。
員工團隊如何與假期請求相關?這裏保護的不變量是什麼?例如,如果同一團隊的其他員工要求假日重疊,員工是否可以申請假期?等等,如果不知道你想要保護什麼不變量,你就無法定義正確的AR邊界。 – plalx
@plalx假設沒有邊界。比方說,可能有一天,沒有人在某一天工作。另一種情況:假設團隊中至少有一個人必須在工作,而其他人則需要甜蜜的假期。我唯一需要知道的是如何建立這些關係的模型。員工不能休息的情況是某種事件的可承受性,不是嗎?另一方面,發出此類請求的員工必須知道他不能發送假期請求,因爲當天沒有員工可以使用。你怎麼看? –
@plalx爲了完成我的回答,員工是發送假期請求的作者,所以另一個'Employee'將有一定的權限接受它,知道是誰發送了它。所以基本上'HolidaysRequest'由一些HolidaysRequestMetadata和'Employee'組成。 –