-
样本架(Rack):实体,有唯一ID,包含多个样本(Sample)。
-
样本(Sample):值对象或实体(如果有唯一标识,例如样本编号)。
-
站点(Station):实体,代表一个处理单元,如分注站、离心站、检测站等。每个站点有唯一ID,并有状态(空闲、忙碌、故障等)。
-
流水线(Pipeline):可以看作是一个领域概念,由一系列站点组成,但调度逻辑可能不直接是流水线,而是调度器。
-
调度器(Scheduler):领域服务,负责根据当前状态和规则决定样本架的下一个站点。
-
传输带(Conveyor):基础设施,负责实际移动样本架。在领域模型中,我们可能只关心调度的逻辑,而实际移动由基础设施服务实现。
限界上下文:整个调度系统作为一个上下文,可能还需要与实验室信息管理系统(LIMS)交互,但这里我们聚焦在调度本身。
战术设计:
-
实体:Rack, Station, 可能还有Sample(如果样本有独立调度需求,但通常调度的是样本架)。
-
值对象:位置(Location),可能包括站点位置和传输带上的位置。
-
领域服务:Scheduler,负责调度决策。
-
领域事件:当样本架到达某个站点、离开站点、站点状态变化时,可能产生事件,用于触发后续操作。
-
仓库:RackRepository, StationRepository,用于持久化。
-
聚合根:Rack和Station可能是聚合根,因为它们有全局标识,并且需要保证一致性边界。
由于我们只是模拟调度逻辑,实际移动由外部控制,我们可以将传输带视为基础设施服务,由它来实际移动样本架,但调度器只做决策。
cpp
// 领域模型核心定义
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
#include <functional>
#include <chrono>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <algorithm>
namespace Domain {
// ===================== 值对象 (Value Objects) =====================
// 值对象是不可变的,通过值进行比较
// 位置坐标
class Location {
public:
Location(int x, int y, int z = 0) : x_(x), y_(y), z_(z) {}
int getX() const { return x_; }
int getY() const { return y_; }
int getZ() const { return z_; }
bool operator==(const Location& other) const {
return x_ == other.x_ && y_ == other.y_ && z_ == other.z_;
}
bool operator!=(const Location& other) const {
return !(*this == other);
}
std::string toString() const {
return "(" + std::to_string(x_) + "," + std::to_string(y_) + "," + std::to_string(z_) + ")";
}
private:
int x_;
int y_;
int z_;
};
// 样本架ID - 值对象
class RackId {
public:
explicit RackId(const std::string& id) : id_(id) {}
const std::string& getId() const { return id_; }
bool operator==(const RackId& other) const { return id_ == other.id_; }
bool operator!=(const RackId& other) const { return !(*this == other); }
bool operator<(const RackId& other) const { return id_ < other.id_; }
private:
std::string id_;
};
// 站点ID - 值对象
class StationId {
public:
explicit StationId(const std::string& id) : id_(id) {}
const std::string& getId() const { return id_; }
bool operator==(const StationId& other) const { return id_ == other.id_; }
bool operator!=(const StationId& other) const { return !(*this == other); }
private:
std::string id_;
};
// 调度优先级
enum class Priority {
HIGH = 0,
NORMAL = 1,
LOW = 2
};
// 样本架状态
enum class RackStatus {
IDLE, // 空闲
LOADED, // 已装载样本
PROCESSING, // 处理中
WAITING, // 等待传输
TRANSFERRING, // 传输中
COMPLETED, // 处理完成
ERROR // 错误
};
// ===================== 实体 (Entities) =====================
// 实体有唯一标识,通过标识进行比较
// 样本实体
class Sample {
public:
Sample(const std::string& id, const std::string& type, Priority priority = Priority::NORMAL)
: id_(id), type_(type), priority_(priority), status_(RackStatus::IDLE) {}
const std::string& getId() const { return id_; }
const std::string& getType() const { return type_; }
Priority getPriority() const { return priority_; }
RackStatus getStatus() const { return status_; }
void setStatus(RackStatus status) { status_ = status; }
private:
std::string id_; // 唯一标识
std::string type_; // 样本类型
Priority priority_; // 处理优先级
RackStatus status_; // 当前状态
};
// 样本架实体 - 聚合根
class Rack : public std::enable_shared_from_this<Rack> {
public:
Rack(const RackId& id, int capacity = 10)
: id_(id), capacity_(capacity), currentLocation_(0, 0, 0), status_(RackStatus::IDLE) {}
const RackId& getId() const { return id_; }
RackStatus getStatus() const { return status_; }
const Location& getLocation() const { return currentLocation_; }
int getSampleCount() const { return static_cast<int>(samples_.size()); }
int getCapacity() const { return capacity_; }
// 业务方法
void loadSample(const Sample& sample) {
if (samples_.size() < capacity_) {
samples_.push_back(sample);
if (status_ == RackStatus::IDLE) {
status_ = RackStatus::LOADED;
}
} else {
throw std::runtime_error("Rack is at full capacity");
}
}
void updateLocation(const Location& newLocation) {
currentLocation_ = newLocation;
if (status_ == RackStatus::WAITING) {
status_ = RackStatus::TRANSFERRING;
}
}
void setStatus(RackStatus status) {
status_ = status;
}
void startProcessing() { status_ = RackStatus::PROCESSING; }
void completeProcessing() { status_ = RackStatus::COMPLETED; }
std::vector<Sample> getSamples() const { return samples_; }
// 检查是否可以处理
bool canProcess() const {
return status_ == RackStatus::LOADED || status_ == RackStatus::WAITING;
}
private:
RackId id_;
int capacity_;
Location currentLocation_;
RackStatus status_;
std::vector<Sample> samples_;
};
// 站点实体
class Station {
public:
Station(const StationId& id, const std::string& name, const Location& location,
const std::vector<std::string>& supportedSampleTypes)
: id_(id), name_(name), location_(location),
supportedSampleTypes_(supportedSampleTypes), isActive_(true) {}
const StationId& getId() const { return id_; }
const std::string& getName() const { return name_; }
const Location& getLocation() const { return location_; }
bool isActive() const { return isActive_; }
// 业务方法:站点是否支持处理该样本架
bool canProcessRack(const std::shared_ptr<Rack>& rack) const {
if (!isActive_) return false;
auto samples = rack->getSamples();
for (const auto& sample : samples) {
if (std::find(supportedSampleTypes_.begin(),
supportedSampleTypes_.end(),
sample.getType()) == supportedSampleTypes_.end()) {
return false;
}
}
return true;
}
void activate() { isActive_ = true; }
void deactivate() { isActive_ = false; }
private:
StationId id_;
std::string name_;
Location location_;
std::vector<std::string> supportedSampleTypes_;
bool isActive_;
};
// ===================== 领域服务 (Domain Services) =====================
// 处理跨多个实件的业务逻辑
// 调度策略接口
class ISchedulingStrategy {
public:
virtual ~ISchedulingStrategy() = default;
// 决定下一个要处理的样本架
virtual std::shared_ptr<Rack> selectNextRack(
const std::vector<std::shared_ptr<Rack>>& availableRacks) = 0;
// 为样本架选择目标站点
virtual StationId selectTargetStation(
const std::shared_ptr<Rack>& rack,
const std::vector<std::shared_ptr<Station>>& availableStations) = 0;
};
// 基于优先级的调度策略
class PrioritySchedulingStrategy : public ISchedulingStrategy {
public:
std::shared_ptr<Rack> selectNextRack(
const std::vector<std::shared_ptr<Rack>>& availableRacks) override {
if (availableRacks.empty()) return nullptr;
// 优先选择有高优先级样本的样本架
auto it = std::max_element(availableRacks.begin(), availableRacks.end(),
[](const auto& a, const auto& b) {
auto samplesA = a->getSamples();
auto samplesB = b->getSamples();
// 简单的优先级比较:检查是否有高优先级样本
bool aHasHigh = std::any_of(samplesA.begin(), samplesA.end(),
[](const Sample& s) { return s.getPriority() == Priority::HIGH; });
bool bHasHigh = std::any_of(samplesB.begin(), samplesB.end(),
[](const Sample& s) { return s.getPriority() == Priority::HIGH; });
if (aHasHigh && !bHasHigh) return false;
if (!aHasHigh && bHasHigh) return true;
// 如果优先级相同,选择样本多的
return samplesA.size() < samplesB.size();
});
return *it;
}
StationId selectTargetStation(
const std::shared_ptr<Rack>& rack,
const std::vector<std::shared_ptr<Station>>& availableStations) override {
for (const auto& station : availableStations) {
if (station->canProcessRack(rack)) {
return station->getId();
}
}
throw std::runtime_error("No suitable station found for rack");
}
};
// ===================== 仓储接口 (Repository Interfaces) =====================
// 定义数据访问契约
class IRackRepository {
public:
virtual ~IRackRepository() = default;
virtual void add(const std::shared_ptr<Rack>& rack) = 0;
virtual void remove(const RackId& id) = 0;
virtual std::shared_ptr<Rack> getById(const RackId& id) = 0;
virtual std::vector<std::shared_ptr<Rack>> getAll() = 0;
virtual std::vector<std::shared_ptr<Rack>> getByStatus(RackStatus status) = 0;
virtual void update(const std::shared_ptr<Rack>& rack) = 0;
};
class IStationRepository {
public:
virtual ~IStationRepository() = default;
virtual void add(const std::shared_ptr<Station>& station) = 0;
virtual std::shared_ptr<Station> getById(const StationId& id) = 0;
virtual std::vector<std::shared_ptr<Station>> getAll() = 0;
virtual std::vector<std::shared_ptr<Station>> getActiveStations() = 0;
};
// ===================== 领域事件 (Domain Events) =====================
class DomainEvent {
public:
virtual ~DomainEvent() = default;
virtual std::string getName() const = 0;
virtual std::string toString() const = 0;
};
class RackStatusChangedEvent : public DomainEvent {
public:
RackStatusChangedEvent(const RackId& rackId, RackStatus oldStatus, RackStatus newStatus)
: rackId_(rackId), oldStatus_(oldStatus), newStatus_(newStatus),
timestamp_(std::chrono::system_clock::now()) {}
std::string getName() const override { return "RackStatusChangedEvent"; }
std::string toString() const override {
auto time = std::chrono::system_clock::to_time_t(timestamp_);
char timeStr[20];
std::strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S", std::localtime(&time));
return "Rack " + rackId_.getId() + " status changed from " +
std::to_string(static_cast<int>(oldStatus_)) + " to " +
std::to_string(static_cast<int>(newStatus_)) + " at " + timeStr;
}
const RackId& getRackId() const { return rackId_; }
RackStatus getOldStatus() const { return oldStatus_; }
RackStatus getNewStatus() const { return newStatus_; }
private:
RackId rackId_;
RackStatus oldStatus_;
RackStatus newStatus_;
std::chrono::system_clock::time_point timestamp_;
};
class RackMovedEvent : public DomainEvent {
public:
RackMovedEvent(const RackId& rackId, const Location& from, const Location& to)
: rackId_(rackId), from_(from), to_(to),
timestamp_(std::chrono::system_clock::now()) {}
std::string getName() const override { return "RackMovedEvent"; }
std::string toString() const override {
auto time = std::chrono::system_clock::to_time_t(timestamp_);
char timeStr[20];
std::strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S", std::localtime(&time));
return "Rack " + rackId_.getId() + " moved from " +
from_.toString() + " to " + to_.toString() + " at " + timeStr;
}
private:
RackId rackId_;
Location from_;
Location to_;
std::chrono::system_clock::time_point timestamp_;
};
// 事件处理器接口
class IEventHandler {
public:
virtual ~IEventHandler() = default;
virtual void handle(const std::shared_ptr<DomainEvent>& event) = 0;
};
// 简单的事件总线
class EventBus {
public:
void subscribe(const std::string& eventName, std::shared_ptr<IEventHandler> handler) {
subscribers_[eventName].push_back(handler);
}
void publish(const std::shared_ptr<DomainEvent>& event) {
auto it = subscribers_.find(event->getName());
if (it != subscribers_.end()) {
for (auto& handler : it->second) {
handler->handle(event);
}
}
}
private:
std::unordered_map<std::string, std::vector<std::shared_ptr<IEventHandler>>> subscribers_;
};
// ===================== 应用服务 (Application Service) =====================
// 协调领域对象完成用例
class RackSchedulingService {
public:
RackSchedulingService(
std::shared_ptr<IRackRepository> rackRepo,
std::shared_ptr<IStationRepository> stationRepo,
std::shared_ptr<ISchedulingStrategy> strategy,
std::shared_ptr<EventBus> eventBus)
: rackRepository_(rackRepo), stationRepository_(stationRepo),
schedulingStrategy_(strategy), eventBus_(eventBus) {}
// 用例:调度样本架到下一个站点
bool scheduleRackToNextStation(const RackId& rackId) {
try {
// 1. 获取样本架
auto rack = rackRepository_->getById(rackId);
if (!rack) {
std::cerr << "Rack not found: " << rackId.getId() << std::endl;
return false;
}
// 2. 检查样本架状态
if (!rack->canProcess()) {
std::cerr << "Rack cannot be processed: " << rackId.getId() << std::endl;
return false;
}
// 3. 获取可用的站点
auto availableStations = stationRepository_->getActiveStations();
if (availableStations.empty()) {
std::cerr << "No active stations available" << std::endl;
return false;
}
// 4. 使用策略选择目标站点
StationId targetStationId = schedulingStrategy_->selectTargetStation(rack, availableStations);
auto targetStation = stationRepository_->getById(targetStationId);
if (!targetStation) {
std::cerr << "Target station not found: " << targetStationId.getId() << std::endl;
return false;
}
// 5. 记录旧位置,更新样本架位置和状态
Location oldLocation = rack->getLocation();
rack->updateLocation(targetStation->getLocation());
rack->setStatus(RackStatus::WAITING);
// 6. 保存更新
rackRepository_->update(rack);
// 7. 发布领域事件
eventBus_->publish(std::make_shared<RackMovedEvent>(
rackId, oldLocation, targetStation->getLocation()));
std::cout << "Scheduled rack " << rackId.getId()
<< " to station " << targetStationId.getId() << std::endl;
return true;
} catch (const std::exception& e) {
std::cerr << "Scheduling failed: " << e.what() << std::endl;
return false;
}
}
// 用例:处理样本架
bool processRack(const RackId& rackId) {
auto rack = rackRepository_->getById(rackId);
if (!rack) return false;
RackStatus oldStatus = rack->getStatus();
rack->startProcessing();
rackRepository_->update(rack);
// 发布状态变更事件
eventBus_->publish(std::make_shared<RackStatusChangedEvent>(
rackId, oldStatus, rack->getStatus()));
// 模拟处理过程
std::this_thread::sleep_for(std::chrono::seconds(1));
oldStatus = rack->getStatus();
rack->completeProcessing();
rackRepository_->update(rack);
eventBus_->publish(std::make_shared<RackStatusChangedEvent>(
rackId, oldStatus, rack->getStatus()));
std::cout << "Processed rack: " << rackId.getId() << std::endl;
return true;
}
// 用例:自动调度下一个样本架
RackId scheduleNextRack() {
auto availableRacks = rackRepository_->getByStatus(RackStatus::LOADED);
if (availableRacks.empty()) {
throw std::runtime_error("No racks available for scheduling");
}
auto nextRack = schedulingStrategy_->selectNextRack(availableRacks);
if (!nextRack) {
throw std::runtime_error("Failed to select next rack");
}
if (scheduleRackToNextStation(nextRack->getId())) {
return nextRack->getId();
}
throw std::runtime_error("Failed to schedule selected rack");
}
private:
std::shared_ptr<IRackRepository> rackRepository_;
std::shared_ptr<IStationRepository> stationRepository_;
std::shared_ptr<ISchedulingStrategy> schedulingStrategy_;
std::shared_ptr<EventBus> eventBus_;
};
} // namespace Domain
// ===================== 基础设施层 (Infrastructure Layer) =====================
// 实现仓储接口,提供具体技术实现
namespace Infrastructure {
// 内存实现的仓储
class InMemoryRackRepository : public Domain::IRackRepository {
public:
void add(const std::shared_ptr<Domain::Rack>& rack) override {
racks_[rack->getId()] = rack;
}
void remove(const Domain::RackId& id) override {
racks_.erase(id);
}
std::shared_ptr<Domain::Rack> getById(const Domain::RackId& id) override {
auto it = racks_.find(id);
return it != racks_.end() ? it->second : nullptr;
}
std::vector<std::shared_ptr<Domain::Rack>> getAll() override {
std::vector<std::shared_ptr<Domain::Rack>> result;
for (const auto& pair : racks_) {
result.push_back(pair.second);
}
return result;
}
std::vector<std::shared_ptr<Domain::Rack>> getByStatus(Domain::RackStatus status) override {
std::vector<std::shared_ptr<Domain::Rack>> result;
for (const auto& pair : racks_) {
if (pair.second->getStatus() == status) {
result.push_back(pair.second);
}
}
return result;
}
void update(const std::shared_ptr<Domain::Rack>& rack) override {
racks_[rack->getId()] = rack;
}
private:
std::unordered_map<Domain::RackId, std::shared_ptr<Domain::Rack>,
std::hash<std::string>> racks_;
};
class InMemoryStationRepository : public Domain::IStationRepository {
public:
void add(const std::shared_ptr<Domain::Station>& station) override {
stations_[station->getId()] = station;
}
std::shared_ptr<Domain::Station> getById(const Domain::StationId& id) override {
auto it = stations_.find(id);
return it != stations_.end() ? it->second : nullptr;
}
std::vector<std::shared_ptr<Domain::Station>> getAll() override {
std::vector<std::shared_ptr<Domain::Station>> result;
for (const auto& pair : stations_) {
result.push_back(pair.second);
}
return result;
}
std::vector<std::shared_ptr<Domain::Station>> getActiveStations() override {
std::vector<std::shared_ptr<Domain::Station>> result;
for (const auto& pair : stations_) {
if (pair.second->isActive()) {
result.push_back(pair.second);
}
}
return result;
}
private:
std::unordered_map<Domain::StationId, std::shared_ptr<Domain::Station>,
std::hash<std::string>> stations_;
};
// 简单的事件处理器实现
class LoggingEventHandler : public Domain::IEventHandler {
public:
void handle(const std::shared_ptr<Domain::DomainEvent>& event) override {
std::cout << "[EVENT] " << event->toString() << std::endl;
}
};
} // namespace Infrastructure
// ===================== 主程序示例 =====================
int main() {
using namespace Domain;
using namespace Infrastructure;
std::cout << "=== 流水线样本架调度系统 (DDD设计) ===\n" << std::endl;
// 1. 初始化基础设施
auto rackRepo = std::make_shared<InMemoryRackRepository>();
auto stationRepo = std::make_shared<InMemoryStationRepository>();
auto schedulingStrategy = std::make_shared<PrioritySchedulingStrategy>();
auto eventBus = std::make_shared<EventBus>();
// 2. 注册事件处理器
auto logger = std::make_shared<LoggingEventHandler>();
eventBus->subscribe("RackStatusChangedEvent", logger);
eventBus->subscribe("RackMovedEvent", logger);
// 3. 创建应用服务
RackSchedulingService schedulingService(rackRepo, stationRepo,
schedulingStrategy, eventBus);
// 4. 初始化领域对象
// 创建站点
stationRepo->add(std::make_shared<Station>(
StationId("ST001"), "样本准备站", Location(0, 0, 0),
std::vector<std::string>{"BLOOD", "URINE"}
));
stationRepo->add(std::make_shared<Station>(
StationId("ST002"), "离心站", Location(10, 0, 0),
std::vector<std::string>{"BLOOD"}
));
stationRepo->add(std::make_shared<Station>(
StationId("ST003"), "检测站", Location(20, 0, 0),
std::vector<std::string>{"BLOOD", "URINE", "CSF"}
));
// 创建样本架并装载样本
auto rack1 = std::make_shared<Rack>(RackId("RACK001"));
rack1->loadSample(Sample("SMP001", "BLOOD", Priority::HIGH));
rack1->loadSample(Sample("SMP002", "BLOOD", Priority::NORMAL));
rack1->setStatus(RackStatus::LOADED);
auto rack2 = std::make_shared<Rack>(RackId("RACK002"));
rack2->loadSample(Sample("SMP003", "URINE", Priority::NORMAL));
rack2->setStatus(RackStatus::LOADED);
auto rack3 = std::make_shared<Rack>(RackId("RACK003"));
rack3->loadSample(Sample("SMP004", "BLOOD", Priority::HIGH));
rack3->loadSample(Sample("SMP005", "CSF", Priority::HIGH));
rack3->setStatus(RackStatus::LOADED);
// 添加到仓储
rackRepo->add(rack1);
rackRepo->add(rack2);
rackRepo->add(rack3);
std::cout << "系统初始化完成,共创建:" << std::endl;
std::cout << "- 站点: " << stationRepo->getAll().size() << " 个" << std::endl;
std::cout << "- 样本架: " << rackRepo->getAll().size() << " 个" << std::endl;
std::cout << std::endl;
// 5. 执行业务用例
std::cout << "=== 开始调度样本架 ===" << std::endl;
try {
// 调度下一个样本架
auto nextRackId = schedulingService.scheduleNextRack();
std::cout << "已调度样本架: " << nextRackId.getId() << std::endl;
// 处理样本架
schedulingService.processRack(nextRackId);
// 调度第二个样本架
auto nextRackId2 = schedulingService.scheduleNextRack();
std::cout << "已调度样本架: " << nextRackId2.getId() << std::endl;
} catch (const std::exception& e) {
std::cerr << "调度错误: " << e.what() << std::endl;
}
// 6. 显示最终状态
std::cout << "\n=== 最终状态 ===" << std::endl;
auto allRacks = rackRepo->getAll();
for (const auto& rack : allRacks) {
std::cout << "样本架 " << rack->getId().getId()
<< " - 状态: " << static_cast<int>(rack->getStatus())
<< " - 位置: " << rack->getLocation().toString()
<< " - 样本数: " << rack->getSampleCount() << std::endl;
}
return 0;
}
目录结构示意图:
pipeline_scheduler/
├── include/
│ └── domain/
│ ├── value_objects/ # 值对象
│ │ ├── location.h
│ │ ├── rack_id.h
│ │ └── station_id.h
│ ├── entities/ # 实体
│ │ ├── sample.h
│ │ ├── rack.h
│ │ └── station.h
│ ├── repositories/ # 仓储接口
│ │ ├── irack_repository.h
│ │ └── istation_repository.h
│ ├── services/ # 领域服务
│ │ ├── ischeduling_strategy.h
│ │ └── priority_scheduling_strategy.h
│ ├── events/ # 领域事件
│ │ ├── domain_event.h
│ │ ├── rack_status_changed_event.h
│ │ └── event_bus.h
│ └── application/ # 应用服务
│ └── rack_scheduling_service.h
├── src/
│ ├── domain/ # 领域层实现
│ │ └── entities/
│ │ ├── sample.cpp
│ │ ├── rack.cpp
│ │ └── station.cpp
│ ├── infrastructure/ # 基础设施层
│ │ ├── inmemory_rack_repository.cpp
│ │ ├── inmemory_station_repository.cpp
│ │ └── logging_event_handler.cpp
│ ├── application/ # 应用层实现
│ │ └── rack_scheduling_service.cpp
│ └── main.cpp
├── tests/ # 单元测试
└── CMakeLists.txt
DDD设计要点说明
-
领域层(Domain):包含了核心业务逻辑
-
值对象:
Location、RackId、StationId等 -
实体:
Sample、Rack(聚合根)、Station -
领域服务:
ISchedulingStrategy和其实现 -
领域事件:
DomainEvent及其子类
-
-
应用层(Application):
RackSchedulingService:协调领域对象完成特定用例
-
基础设施层(Infrastructure):
-
仓储的内存实现
-
事件处理器的具体实现
-
-
依赖倒置原则:
-
高层模块(应用服务)依赖抽象(仓储接口)
-
具体实现在基础设施层
-
-
限界上下文:
-
调度上下文:处理样本架的调度逻辑
-
可以扩展其他上下文:样本管理、仪器控制等
-
扩展建议
-
添加仓储的数据库实现:替换内存实现为数据库持久化
-
实现更复杂的调度策略:基于时间、优先级、仪器负载等
-
添加领域事件处理:如样本架完成处理时自动触发下一步调度
-
实现CQRS模式:将查询和命令分离,提高查询性能
-
添加单元测试:针对每个领域对象和服务的测试
-
集成消息队列:用于处理异步领域事件
-
添加防腐层:如果需要与其他系统集成
最佳实践总结
-
保持聚合小巧:一个聚合只包含必须一起修改的对象
-
通过ID引用其他聚合:避免直接对象引用
-
最终一致性:跨聚合的业务规则通过领域事件实现最终一致性
-
聚合根是门卫:所有修改必须通过聚合根的方法
-
聚合根是事务边界:设计时要考虑并发控制
-
聚合根包含业务规则:封装最重要的不变量