红帽构建的 OptaPlanner 时间表项目的目标是将每节分配给一个时间段和一个房间。为此,请添加三个类: Timeslot、Lesson 和 Room,如下图所示:
时间段没有日期,因为高校的计划只每周重复。无法进行持续 规划。次性被称为 问题事实,因为在解决过程中不会有定时实例变化。此类类不需要任何特定于 OptaPlanner 的注解。
房间 实例在解决过程中不会改变,因此 Room 也是 问题。
在寻求过程中,OptaPlanner 改变了 lesson 类的 timelot 和 room 字段,从而将每个较小的时间分配给一个时间段和一个房间。 因为 OptaPlanner 更改了这些字段,所以 lesson 是一个 规划实体 :
上图中的大多数字段包含输入数据,但 orange 字段除外。在输入数据中 未分配的 时间和房间 字段(null),并在输出数据中分配(而不是 null)。OptaPlanner 在解决过程中更改这些字段。这些字段称为规划变量。为了 OptaPlanner 可以识别它们,timelot 和 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 或 abrt 日志,如稍后所示。
创建 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 知道这个类在解决过程中发生了变化,因为它包含一个或多个计划变量。
time lot 字段具有 @PlanningVariable 注释,因此 OptaPlanner 知道它可以更改其值。为了查找要分配给此字段的潜在的 Timeslot 实例,OptaPlanner 使用 valueRangeProviderRefs 属性连接到一个提供 List<Timeslot> 的值供应商。有关值范围供应商的信息,请参阅 第 13.4 节 “在规划解决方案中收集域对象”。
出于同样原因,room 字段还具有 @PlanningVariable 注释。