假设我们有以下Service
:
public class ExoplayerService extends Service {
public static Intent createIntent(Context context, LectureCompositeId id) {
Intent intent = new Intent(context, ExoplayerService.class);
intent.putExtra(EXTRA_LECTURE_COMPOSITE_ID, (Parcelable) id);
return intent;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String action = null;
LectureCompositeId lectureCompositeId = null;
if (intent != null) {
action = intent.getAction();
lectureCompositeId = intent.getParcelableExtra(EXTRA_LECTURE_COMPOSITE_ID);
}
L.leaveBreadcrumb(TAG, "onStartCommand >> startId: " + startId + " flags: " + flags +
" intent: " + intent + "action: " + action + " lectureCompositeId: " + lectureCompositeId);
// Actions are send by Notification and lock screen controls as intent params
if (intent != null) {
if (ACTION_SHUTDOWN.equals(action) || ACTION_SHUTDOWN_TASK.equals(action)) {
boolean fromNotification = intent.getBooleanExtra(EXTRA_SOURCE_NOTIFICATION, false);
attemptShutdown(startId, fromNotification, ACTION_SHUTDOWN_TASK.equals(action));
} else if (StringUtils.isNotBlank(action)) {
exoplayerManager.ensureLecture(lectureCompositeId);
handleNotificationMediaButtonAction(action);
} else {
initPlayerService();
}
}
return START_STICKY;
}
/**
* Queue a shutdown of the service. Ensures requests that need a notification have a chance to process.
*/
private void queueShutdown(boolean taskRemoved) {
Intent shutdown = new Intent(this, ExoplayerService.class);
if (taskRemoved) {
shutdown.setAction(ACTION_SHUTDOWN_TASK);
} else {
shutdown.setAction(ACTION_SHUTDOWN);
}
startService(shutdown);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
// other methods
}
当我们想添加一个新的aggregate root
时,我们需要确保它不会与现有的冲突。这就是说public class Resource
{
public IEnumerable<Schedule> schedules {get;private set;}
...
}
确保schedule
方法的不变性。
另一方面,aggregate root
的删除没有不变量。如果我们使用resource.AddSchedule(schedule)
删除schedule
,则需要预先加载所有Resource aggregate root
才能删除一个。
基于此,我们是否应该将schedule
提升为schedules
,仅加载所需的Schedule
,然后将其删除?还是应该继续使用以前的aggregate root
?
答案 0 :(得分:1)
当我们想添加一个新时间表时,我们需要确保它不会与现有时间表发生冲突。
您要在此处实现的目标的总称是set validation。
如果需要绝对保证集合中没有冲突的条目(有时称为“立即一致性”),则必须确保在检查时不会同时更改条目。这意味着您在检查中所关心的值必须成为检查它们的汇总的一部分-我们需要确保答案在我们下面不会改变。
更常见的情况是“尽力而为”就足够了,并且有一些协议可以解决贯穿裂缝的冲突。在这种情况下,您通常可以将集合视为标识符列表,而不是值列表。因此,详细信息可以保留在“计划”聚合中,而“资源”聚合仅跟踪计划成员身份。
还有一个特殊的情况-如果时间表是值而不是实体...意味着给定时间表的详细信息是不可变的,那么您也许也可以吃蛋糕-为每个时间表计算一个唯一的哈希计划,并将哈希值存储在Resource中,以后可以在必要时将其用于查找不可变的计划。
这里的很大一部分工作是正确了解业务需求的细节。在大多数成熟的业务域中,冲突经常发生,以至于存在解决冲突的协议。换句话说,race conditions don't exist。
微妙的时间差异不应改变核心业务行为。
答案 1 :(得分:0)
在实践上,您的用户最有可能提出以下两个建议?
就个人而言,我会避免过早的优化,否则可能会使您日后陷入困境。
答案 2 :(得分:0)
基于此,我们是否应该将Schedule提升为聚合根
如果Schedule
拥有自己的生命周期,那么无论如何它都必须是一个聚合,这会稍微改变您的设计。
但是,假设您在Resource
-> Schedule
之间的关系与Order
-> OrderItem
相同,那么您总是可以让存储库公开一个更简单的删除Schedule
:
public interface IResourceRepository
{
void Add(Resource resource);
void RemoveSchedule(Resource resource, Resource.Schedule schedule); // or some such
}
对于Order
,鉴于存在可能可能是相关的不变量,这可能不会起作用。
更新 :
如果您的Schedule
是一个聚合根,那么您可能会独立于Resource
以及之前创建它。正如{VoiceOfUnreason所提到的那样,Schedule
的唯一性属于集合验证的范围。这样,您的Resource
仍然需要一个对Schedule
实例的引用列表,但是这些引用将仅仅是Id
或某个包含Id
以及其他任何相关对象的值对象位。 Resource
会强制确保您没有重复的时间表。
为了从资源中删除计划,您将回到第一个选项:加载Resource
并删除相关计划Id
或直接“通过存储库将其删除”。
总是存在“硬性对软性删除”事件,通常应该只更改状态(“软性删除”),因为问题较少。然后,Schedule
的硬删除可能会被DRI在数据存储上停止(如果已配置),或者将删除级联到相关表。