18.2. 对域对象建模
红帽构建的 OptaPlanner timetable 项目的目标是为每个课程分配时间插槽和房间。要做到这一点,请添加三个类,Timeslot , lesson , 和 Room,如下图所示:

timeslot
Timeslot 类代表了在课程时的间隔,例如 Monday 10:30 - 11:30 或 Tuesday 13:30 - 14:30。在这个示例中,所有时间插槽都有相同的持续时间,在 lunch 或其他间没有时间插槽。
时间段没有日期,因为高校计划每周都会重复。不需要 持续规划。一个 timeslot 被称为 问题,因为在 解决过程中没有 Timeslot 实例改变。此类类不需要任何 OptaPlanner 特定注解。
房间
Room 类代表一个跟踪课程的位置,例如 Room A 或 Room B。在这个示例中,所有房间都没有容量限制,它们可以容纳所有课程。
房间 实例在解决时 不会改变,因此也 是一个问题。
lesson
在短时间内,由 Lesson 类表示,教员向一组学员提供主题,例如 Math by A.Turing for 9th grade 或 Chemistry by M.Curie for 10th grade。如果每周由同一生组多次学习一个主题,则有多个仅通过 id 区分的 lesson 实例。例如,第 9 个评级每周有 6 个数个。
在解决期间,OptaPlanner 更改了 Lesson 类的 timeslot 和 room 字段,为每个课程分配时间插槽和房间。因为 OptaPlanner 更改这些字段,所以 lesson 是一个 规划实体 :

上图中的大部分字段包含输入数据,但 orange 字段除外。一个 lesson 的 timeslot 和 room 字段在输入数据中未分配(空 ),并在输出数据中分配(非 )。OptaPlanner 在解决过程中更改这些字段。此类字段称为计划变量。为了让 OptaPlanner 识别它们,nulltimeslot 和 room 字段都需要 @PlanningVariable 注释。它包含类 lesson 需要一个 @PlanningEntity 注释。
流程
创建
src/main/java/com/example/domain/Timeslot.java类:package com.example.domain; import java.time.DayOfWeek; import java.time.LocalTime; public class Timeslot { private DayOfWeek dayOfWeek; private LocalTime startTime; private LocalTime endTime; private Timeslot() { } public Timeslot(DayOfWeek dayOfWeek, LocalTime startTime, LocalTime endTime) { this.dayOfWeek = dayOfWeek; this.startTime = startTime; this.endTime = endTime; } @Override public String toString() { return dayOfWeek + " " + startTime.toString(); } // ******************************** // Getters and setters // ******************************** public DayOfWeek getDayOfWeek() { return dayOfWeek; } public LocalTime getStartTime() { return startTime; } public LocalTime getEndTime() { return endTime; } }注意
toString ()方法保持输出短,以便更轻松地阅读 OptaPlanner 的DEBUG或TRACE日志,如稍后所示。创建
src/main/java/com/example/domain/Room.java类:package com.example.domain; public class Room { private String name; private Room() { } public Room(String name) { this.name = name; } @Override public String toString() { return name; } // ******************************** // Getters and setters // ******************************** public String getName() { return name; } }创建
src/main/java/com/example/domain/Lesson.java类:package com.example.domain; import org.optaplanner.core.api.domain.entity.PlanningEntity; import org.optaplanner.core.api.domain.variable.PlanningVariable; @PlanningEntity public class Lesson { private Long id; private String subject; private String teacher; private String studentGroup; @PlanningVariable(valueRangeProviderRefs = "timeslotRange") private Timeslot timeslot; @PlanningVariable(valueRangeProviderRefs = "roomRange") private Room room; private Lesson() { } public Lesson(Long id, String subject, String teacher, String studentGroup) { this.id = id; this.subject = subject; this.teacher = teacher; this.studentGroup = studentGroup; } @Override public String toString() { return subject + "(" + id + ")"; } // ******************************** // Getters and setters // ******************************** public Long getId() { return id; } public String getSubject() { return subject; } public String getTeacher() { return teacher; } public String getStudentGroup() { return studentGroup; } public Timeslot getTimeslot() { return timeslot; } public void setTimeslot(Timeslot timeslot) { this.timeslot = timeslot; } public Room getRoom() { return room; } public void setRoom(Room room) { this.room = room; } }Lesson类具有一个@PlanningEntity注释,因此 OptaPlanner 知道此类在解决过程中发生了变化,因为它包含一个或多个计划变量。timeslot字段具有一个@PlanningVariable注释,因此 OptaPlanner 知道它可以更改其值。为了找到潜在的Timeslot实例来分配给此字段,OptaPlanner 使用valueRangeProviderRefs属性连接到提供List<Timeslot> 的值范围供应商。有关值范围供应商的信息,请参阅 第 18.4 节 “在规划解决方案中收集域对象”。room字段还具有@PlanningVariable注释,原因相同。