SeatFlow.Core 层的领域实体、策略接口、领域服务和能力系统
本页目录
全部文档
Core 层详解
SeatFlow.Core 是 SeatFlow 的领域核心层,负责定义业务实体、策略接口和领域服务。它不依赖任何其他项目,仅引用标准 .NET 库。
领域实体
Student (SeatFlow.Core/Models/Student.cs)
学生是排座系统的基本操作对象。
public class Student
{
public string Id { get; set; } // 唯一标识
public string Name { get; set; }
public float? Height { get; set; } // 身高(cm),用于前排策略筛选
public Gender? Gender { get; set; }
public bool NeedsFrontRow { get; set; } // 是否需要前排(CSV/XLSX 导入字段)
// 轮换记录(环形缓冲区,容量 10)
public CircularHistory<string> RecentSeatHistory { get; set; } = new(10);
// 扩展数据挂载点(插件使用)
public AttributeBag Extensions { get; set; } = new();
}
Seat 体系 (SeatFlow.Core/Models/Seat.cs)
座位采用抽象类和派生类的多态设计:
Seat (abstract)
├── GridSeat — 网格布局(Row, Column)
├── PolarSeat — 极坐标布局(Ring, Angle)
└── FreeformSeat — 自由点布局(X, Y)
核心属性:
public abstract class Seat
{
public string Id { get; set; } // 逻辑 ID
public abstract SeatType Type { get; } // Grid / Polar / Freeform
public string LogicalGroup { get; set; } // 逻辑分组
public abstract object GeometryData { get; }
public bool IsAvailable { get; set; } = true;
public bool IsFixed { get; set; } // 固定座位标记
public string OccupantId { get; set; } // 就坐学生 ID
public AttributeBag Extensions { get; set; } = new();
}
多态序列化通过 SeatJsonConverter(在 SeatFlow.Infrastructure 中)实现,使用 Type 鉴别器字段("Grid" / "Polar" / "Freeform")。
ClassroomLayoutDefinition (SeatFlow.Core/Models/ClassroomLayoutDefinition.cs)
教室布局的完整定义,支持三种布局类型:
public class ClassroomLayoutDefinition
{
public string LayoutType { get; set; } // "Grid" | "Polar" | "Freeform"
public LayoutMetadata Metadata { get; set; } // 布局特定元数据
public List<Seat> Seats { get; set; }
public List<Obstacle> Obstacles { get; set; } // 柱子、讲台等障碍物
}
布局类型同时序列化为数字(layoutType: 0=Grid, 1=Polar, 2=Freeform)和字符串(layoutTypeString)。
SeatingWorkspace (SeatFlow.Core/Workspace/SeatingWorkspace.cs)
排座工作区,是所有策略操作的核心上下文。提供可修改的座位视图并记录操作消息。
public class SeatingWorkspace
{
public IReadOnlyList<Student> Students { get; }
// 核心操作
public bool TryAssignSeat(string seatId, string studentId, out string error);
public IEnumerable<Seat> GetEmptySeats();
public IEnumerable<Seat> FindSeats(Func<Seat, bool> predicate);
public SeatingPlan BuildSeatingPlan();
// 消息系统
public IReadOnlyList<StrategyMessage> Messages { get; }
public void LogWarning(string strategyId, string displayName, string messageKey, params object?[] args);
public void LogError(string strategyId, string displayName, string messageKey, params object?[] args);
// 能力系统
public void RegisterCapabilities(IEnumerable<string> capabilities);
public bool TryMarkFixed(string seatId, string studentId, string strategyId,
string displayName, out string error);
}
SeatingPlan (SeatFlow.Core/Models/SeatingPlan.cs)
管道执行的最终输出,包含所有座位到学生的分配映射。
其他模型类型
策略配置声明相关的模型(SeatFlow.Core.Models):
StrategyParameterDefinition— 策略参数定义StrategyCodeBlock— 策略配置块声明StrategyFieldDefinition— 字段定义StrategyDatasetConfig/StrategyConfigRow— 持久化配置行- 枚举:
StrategyFieldType、StrategyDataType、StrategyDisplayMode
策略接口
ISeatingStrategy (独立策略)
public interface ISeatingStrategy
{
string Id { get; }
string Name { get; }
int Priority { get; set; }
bool IsEnabled { get; set; }
Task<StrategyExecutionResult> ExecuteAsync(
SeatingWorkspace workspace, CancellationToken cancellationToken);
ValidationResult ValidateConfiguration();
}
独立策略由外部管道编排执行,按 Priority 降序依次操作同一个 SeatingWorkspace。
IDependentSeatingStrategy (依赖策略)
public interface IDependentSeatingStrategy
{
string Id { get; }
string Name { get; }
string DisplayName { get; }
int Priority { get; set; }
bool IsEnabled { get; set; }
Task<DependentEvaluationResult> EvaluateAsync(
SeatingWorkspace workspace, Student student, Seat targetSeat,
IRandomFillContext context, CancellationToken ct);
ValidationResult ValidateConfiguration();
/// <summary>
/// 告知策略在 RandomFill 循环开始前已被前序策略分配的学生 ID。
/// </summary>
void SetPriorAssignedStudentIds(HashSet<string> ids) { }
/// <summary>
/// 返回此策略认为有特殊约束、应优先分配以减少重掷的学生 ID 集合。
/// </summary>
HashSet<string> GetConstrainedStudentIds() => [];
}
依赖策略不在外部管道中执行,而是在 RandomFillStrategy 的分配循环中运行。每次 RandomFill 选出 (student, seat) 对后,按内部 Priority 降序依次调用 EvaluateAsync。
DependentEvaluationResult 有三种结果:
- Approve — 批准分配
- Reject — 请求重掷(RandomFill 选择下一个随机座位重试)
- Handled — 依赖策略已自行完成分配(含连携修改),RandomFill 跳过
TryAssignSeat
7 条内置策略
| 策略 | Priority | 类型 | 文件 | 职责 |
|---|---|---|---|---|
| FixedSeatStrategy | 100 | 独立 | Strategies/FixedSeatStrategy.cs |
锁定固定座位 (IsFixed=true),后续策略自动排除 |
| FrontRowRotationStrategy | 50 | 独立 | Strategies/FrontRowRotationStrategy.cs |
按需求分数选出学生,Fisher-Yates 洗牌后随机分布前排 |
| DeskMateStrategy | 50 (上下文) | 依赖 | Strategies/DeskMateStrategy.cs |
在 RandomFill 中检查同桌关系,协调同行邻列分配 |
| GenderRestrictedSeatStrategy | 45 (上下文) | 依赖 | Strategies/GenderRestrictedSeatStrategy.cs |
检查座位性别限制,不匹配时重定向到匹配空座 |
| NoRepeatDeskMateStrategy | 40 (上下文) | 依赖 | Strategies/NoRepeatDeskMateStrategy.cs |
检查相邻已占座是否与历史同桌重复 |
| RandomFillStrategy | 1 | 独立+宿主 | Strategies/RandomFillStrategy.cs |
兜底填充,托管依赖策略执行 |
| DefragStrategy | 0 | 独立 | Strategies/DefragStrategy.cs |
后置碎片整理(默认禁用) |
策略管道编排
FixedSeat(100) → FrontRowRotation(50) → RandomFill(1) → Defrag(0)
│
┌────────┼────────┐
▼ ▼ ▼
DeskMate Gender NoRepeat
(50) Restrict DeskMate
(45) (40)
策略配置清单
每种策略的 UI 配置由 manifest JSON 文件声明式驱动(SeatFlow.Core/Strategies/Manifests/{Id}.json),包含:
visible— 策略可见性(默认 true,false 时完全排除)isIndependent— 是否为独立策略(默认 true)manifestVersion— 清单格式版本capabilities[]— 策略能力声明parameters[]— 策略级全局参数codeBlocks[]— 按数据集/会场的配置块messages— 策略执行消息 i18n 模板
领域服务
位于 SeatFlow.Core/DomainServices/:
| 服务 | 文件 | 职责 |
|---|---|---|
| ObstacleProcessor | ObstacleProcessor.cs |
处理教室中的障碍物(柱子、讲台等),调整座位布局 |
| SeatGeometryHelper | SeatGeometryHelper.cs |
座位几何计算,如相邻判断、距离计算 |
| StrategyManifestProvider | StrategyManifestProvider.cs |
加载和提供策略 manifest JSON(嵌入资源),解析声明式配置 |
| SeatAdjacencyHelper | SeatAdjacencyHelper.cs |
座位相邻关系辅助,判断同行、同桌、邻座等 |
工具类
位于 SeatFlow.Core/Utilities/:
| 工具 | 文件 | 用途 |
|---|---|---|
CircularHistory<T> |
CircularHistory.cs |
环形缓冲区,固定容量(Student.RecentSeatHistory 容量为 10),自动覆盖最旧记录 |
AttributeBag |
AttributeBag.cs |
扩展数据挂载点,允许插件向实体附加自定义数据 |
数据提供者接口
位于 SeatFlow.Core/Abstractions/:
| 接口 | 用途 |
|---|---|
IStudentProvider |
学生数据加载(从文件/流读取学生列表) |
IVenueRepository |
会场数据持久化 |
IStudentDatasetRepository |
学生数据集管理 |
ISeatingPlanExporter |
排座结果导出 |
这些接口由 Infrastructure 层实现,通过 DI 注入到 Application 层使用。
能力系统
位于 SeatFlow.Core/Strategies/Capability.cs:
Capability 提供了一种声明式的能力约束机制——策略需在 manifest 中声明能力,运行时方可调用对应接口。
public static class Capability
{
public const string MarkFixedSeat = "MarkFixedSeat";
// 未来在此追加新常量
}
public interface IFixedSeatCapability
{
bool TryMarkFixed(string seatId, string studentId,
string strategyId, string displayName, out string error);
}
执行链:
ApplicationFacade从 manifest 读取capabilities- 调用
workspace.RegisterCapabilities(capabilities)注册 - 策略调用
TryMarkFixed()时,workspace 校验声明状态 - 未声明则拒绝并记录警告
SeatingWorkspace 实现 IFixedSeatCapability,IPluginWorkspace 直接暴露 TryMarkFixed 方法供插件使用。