10.2. 对域对象建模
红帽构建的 OptaPlanner 时间项目的目标是将每次项目分配到一个时间插槽和间间。要做到这一点,添加三个类: Timeslot、init on 和 Room,如下图所示:
timeslot
Timeslot 类代表当减少活动为过期的时间间隔时,例如,Monday 10:30 - 11:30 或 Tuesday 13:30 - 14:30。在这个示例中,所有时间段都有相同的持续时间,在 lunch 或其他中断过程中没有时间插槽。
一个时间插槽没有日期,因为每周计划只重复一次。不需要 持续规划。timeslot 被称为 问题事实,因为公司不会更改 Timeslot 实例。此类类不需要任何特定于 OptaPlanner 的注解。
房间
Room 类代表更小活动的位置,例如 Room A 或 Room B。在本例中,所有房间都没有容量限制,它们可以容纳所有定义。
空间 实例在竞争过程中不会改变,因此 Room 也是 问题事实。
lesson
在小时间中,由周一类代表,受一组参与者代表的规定,例如,A.Turing for 9th rating 或 Chemistry by M.Curie 代表第 10 等级。如果一个主题是按同一站组相同的每周的多次,则有多个仅可通过 id 区分的实例。例如,第 9 等级每周有六个数学。
在 OptaPlanner 期间,OptaPlanner 会更改周一类的 timeslot 和 room 字段,以将每个小时间分配给一个时间插槽和房间。因为 OptaPlanner 更改这些字段,因此 Apple on 是一个 规划实体 :
上图中的大部分字段都包含输入数据,但 orange 字段除外。在输入数据中取消分配较少的 timeslot 和 room 字段,并在输出数据中分配(而非 )。OptaPlanner 在参与过程中会更改这些字段。此类字段称为 规划变量。为了使 OptaPlanner 能够识别它们,nulltimeslot 和 room 字段都需要 @PlanningVariable 注释。它们包含类属性需要 @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; } }bring
on类有一个@PlanningEntity注释,因此 OptaPlanner 知道该类在周五期间发生了变化,因为它包含一个或多个规划变量。timeslot字段有一个@PlanningVariable注释,因此 OptaPlanner 知道它可以更改其值。要查找分配给此字段的潜在Timeslot实例,OptaPlanner 使用valueRangeProviderRefs属性连接到提供List<Timeslot> 的值范围供应商。有关值范围供应商的详情,请查看 第 10.4 节 “在计划解决方案中收集域对象”。由于同样原因,
room字段也有一个@PlanningVariable注释。