0

In OptaPlanner Nurse Rostering example, there are SkillProficiency class:

public class SkillProficiency extends AbstractPersistable {

    private Employee employee;
    private Skill skill;

    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }

    public Skill getSkill() {
        return skill;
    }

    public void setSkill(Skill skill) {
        this.skill = skill;
    }

    @Override
    public String toString() {
        return employee + "-" + skill;
    }

}

Here is the Employee class:

public class Employee extends AbstractPersistable {

    private String code;
    private String name;
    private Contract contract;

    private Map<ShiftDate, DayOffRequest> dayOffRequestMap;
    private Map<ShiftDate, DayOnRequest> dayOnRequestMap;
    private Map<Shift, ShiftOffRequest> shiftOffRequestMap;
    private Map<Shift, ShiftOnRequest> shiftOnRequestMap;

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Contract getContract() {
        return contract;
    }

    public void setContract(Contract contract) {
        this.contract = contract;
    }

    public int getWeekendLength() {
        return getContract().getWeekendLength();
    }

    public Map<ShiftDate, DayOffRequest> getDayOffRequestMap() {
        return dayOffRequestMap;
    }

    public void setDayOffRequestMap(Map<ShiftDate, DayOffRequest> dayOffRequestMap) {
        this.dayOffRequestMap = dayOffRequestMap;
    }

    public Map<ShiftDate, DayOnRequest> getDayOnRequestMap() {
        return dayOnRequestMap;
    }

    public void setDayOnRequestMap(Map<ShiftDate, DayOnRequest> dayOnRequestMap) {
        this.dayOnRequestMap = dayOnRequestMap;
    }

    public Map<Shift, ShiftOffRequest> getShiftOffRequestMap() {
        return shiftOffRequestMap;
    }

    public void setShiftOffRequestMap(Map<Shift, ShiftOffRequest> shiftOffRequestMap) {
        this.shiftOffRequestMap = shiftOffRequestMap;
    }

    public Map<Shift, ShiftOnRequest> getShiftOnRequestMap() {
        return shiftOnRequestMap;
    }

    public void setShiftOnRequestMap(Map<Shift, ShiftOnRequest> shiftOnRequestMap) {
        this.shiftOnRequestMap = shiftOnRequestMap;
    }

    public String getLabel() {
        return "Employee " + name;
    }

    @Override
    public String toString() {
        return code + "(" + name + ")";
    }

}

And also the Skill class:

public class Skill extends AbstractPersistable {

    private String code;

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    @Override
    public String toString() {
        return code;
    }

}

I wonder why it choose to use a SkillProficiency class rather than Embedded the skill variable inside the Employee class? Would it be more simple if we embedded it? There must a good reason behind this decision, but I just can't figure it out. If anybody know, please share it with me. And also, it is okay if I embedded the skill variable inside the Employee class? What will be the bad effect of doing it? Thanks and regards.

the.wizard
  • 1,079
  • 1
  • 9
  • 25
  • post the code so that we can see what you are talking about. – David Lavender Mar 31 '15 at 12:55
  • @MrSpoon: I have just posted the code to give you more detail explaination. thanks. – the.wizard Mar 31 '15 at 13:10
  • 2
    It's a many to many relation, each employee can have 0+ skills. If not for other, it makes easier searching for all employees with a certain skill and searching all skills of an employee. – grudolf Mar 31 '15 at 15:18
  • @grudolf : could you explain it more detail? Maybe with some examples will be very good. Please make an answer with your detail explanation and examples. Thanks. – the.wizard Mar 31 '15 at 17:23

1 Answers1

2

It's a class diagram design choice really. Maybe even a matter of taste.

Employee to Skill is a ManyToMany relationship (see also grudolf's comment). In such cases, I prefer to design the ManyToMany relationshap as a class too. This has a few advantages:

  • Very similar to how it's table would look in a relational database (which makes integration with JPA probably easier)
  • Extendability: if at some point in the future, we want to rate the skill of an employee, we can just add a field int rating to SkillProficiency.
  • Generally easier to assert model consistency.

You can easily extend this model to add a List<SkillProficiency> proficiencyList on class Employee (and/or on class Skill for that matter). The only reason I didn't do that, is because I had no need of it yet.

The alternative design (which I don't like) is to have class Employee have a List<Skill> and class Skill have a List<Employee>. There's nothing in OptaPlanner preventing you from using that model: we don't want to force design decisions on you. But I do fear that writing an efficient scoreDRL with that model might be harder...

Geoffrey De Smet
  • 26,223
  • 11
  • 73
  • 120