红帽构建的 OptaPlanner timetable 项目的目标是为每个课程分配时间插槽和房间。要做到这一点,请添加三个类,Timeslot
,
lesson , 和 Room
,如下图所示:
时间段没有日期,因为高校计划每周都会重复。不需要 持续规划 。一个 timeslot 被称为 问题,因为在 解决过程中没有 Timeslot
实例改变。此类类不需要任何 OptaPlanner 特定注解。
房间
实例在解决时 不会改变
,因此也 是一个问题 。
在解决期间,OptaPlanner 更改了 Lesson
类的 timeslot
和 room
字段,为每个课程分配时间插槽和房间。因为 OptaPlanner 更改这些字段,所以 lesson 是一个 规划实体 :
上图中的大部分字段包含输入数据,但 orange 字段除外。一个 lesson 的 timeslot
和 room
字段在输入数据中未分配(空 ),并在输出数据中分配(非 null
)。OptaPlanner 在解决过程中更改这些字段。此类字段称为计划变量。为了让 OptaPlanner 识别它们,timeslot
和 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>
; 的值范围供应商。有关值范围供应商的信息,请参阅 第 18.4 节 “在规划解决方案中收集域对象” 。
room
字段还具有 @PlanningVariable
注释,原因相同。