红帽构建的 OptaPlanner timetable 项目旨在为每个时间插槽和房间分配。要做到这一点,添加三个类、Timeslot
、Lesson
和 Room
,如下图所示:
时间插槽没有日期,因为高校的计划仅每周重复。不需要 持续规划。一个时间被认为是个问题,因为在解决 过程中,实例不会发生改变。
此类类不需要任何特定于 OptaPlanner 的注解。
空间
实例在解决过程中不会改变,因此 Room
也是 问题事实。
在解决期间,OptaPlanner 会改变下课的计时和 房间
字段,以将每个上课时间分配到一个时间插槽和房间。
因为 OptaPlanner 更改了这些字段,所以 Lesson
是一个 计划实体 :
上图中的大多数字段都包含输入数据,但 orange 字段除外。在输入数据中未分配(空),并在输出数据中分配(非 null
)字段的不计时和 房间
字段。
在解决过程中,OptaPlanner 会更改这些字段。此类字段称为规划变量。为了使 OptaPlanner 能够识别它们,lot 和 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;
}
}
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;
}
}
Copy to Clipboard
Copied!
Toggle word wrap
Toggle overflow
注意 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;
}
}
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;
}
}
Copy to Clipboard
Copied!
Toggle word wrap
Toggle overflow
创建 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;
}
}
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;
}
}
Copy to Clipboard
Copied!
Toggle word wrap
Toggle overflow
Lesson
类具有 @PlanningEntity
注释,因此 OptaPlanner 知道该类在解决问题过程中发生了变化,因为它包含一个或多个规划变量。
timeslot
字段具有 @PlanningVariable
注释,因此 OptaPlanner 知道它可以更改其值。要查找分配给此字段的潜在 Timeslot
实例,OptaPlanner 使用 valueRangeProviderRefs
属性连接到提供 List<Timeslot
> 来选择的值范围供应商。有关值范围供应商的信息,请参阅 第 10.4 节 “在规划解决方案中收集域对象”。
room
字段也具有 @PlanningVariable
注释,理由相同。