Skip to content

Commit 4812e11

Browse files
committed
Add Job.Type enum to replace instanceof checks
- Introduces Type enum (SHIPMENT, PICKUP_SERVICE, DELIVERY_SERVICE, BREAK_SERVICE) - Replaces instanceof type checks with semantic getType() method - Maintains backward compatibility with default implementation - Improves code readability and type safety - Makes adding new job types more straightforward Part of ongoing effort to reduce type checking and improve domain model clarity.
1 parent 287c5ce commit 4812e11

27 files changed

+502
-410
lines changed

jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/toolbox/AlgorithmEventsRecorder.java

+5-6
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import com.graphhopper.jsprit.core.algorithm.ruin.listener.RuinListener;
2828
import com.graphhopper.jsprit.core.problem.AbstractActivity;
2929
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
30-
import com.graphhopper.jsprit.core.problem.job.Delivery;
3130
import com.graphhopper.jsprit.core.problem.job.Job;
3231
import com.graphhopper.jsprit.core.problem.job.Service;
3332
import com.graphhopper.jsprit.core.problem.job.Shipment;
@@ -145,7 +144,7 @@ private String getNodeId(TourActivity act) {
145144
Job job = ((TourActivity.JobActivity) act).getJob();
146145
if (job instanceof Service) {
147146
nodeId = job.getId();
148-
} else if (job instanceof Shipment) {
147+
} else if (job.getJobType().isShipment()) {
149148
if (act.getName().equals("pickupShipment")) nodeId = getFromNodeId((Shipment) job);
150149
else nodeId = getToNodeId((Shipment) job);
151150
}
@@ -166,7 +165,7 @@ public void ruinEnds(Collection<VehicleRoute> routes, Collection<Job> unassigned
166165
public void removed(Job job, VehicleRoute fromRoute) {
167166
if (!record()) return;
168167
if (job instanceof Service) removeService(job, fromRoute);
169-
else if (job instanceof Shipment) removeShipment(job, fromRoute);
168+
else if (job.getJobType().isShipment()) removeShipment(job, fromRoute);
170169
}
171170

172171
private void removeShipment(Job job, VehicleRoute fromRoute) {
@@ -309,7 +308,7 @@ private void addJob(Job job) {
309308
Service service = (Service) job;
310309
addNode(service.getId(), service.getLocation().getCoordinate());
311310
markService(service);
312-
} else if (job instanceof Shipment) {
311+
} else if (job.getJobType().isShipment()) {
313312
Shipment shipment = (Shipment) job;
314313
String fromNodeId = getFromNodeId(shipment);
315314
addNode(fromNodeId, shipment.getPickupLocation().getCoordinate());
@@ -329,7 +328,7 @@ private void markShipment(Shipment shipment) {
329328
}
330329

331330
private void markService(Service service) {
332-
if (service instanceof Delivery) {
331+
if (service.getJobType().isDelivery()) {
333332
markDelivery(service.getId());
334333
} else {
335334
markPickup(service.getId());
@@ -407,7 +406,7 @@ public void informBeforeJobInsertion(Job job, InsertionData data, VehicleRoute r
407406

408407
private void insertJob(Job job, InsertionData data, VehicleRoute route) {
409408
if (job instanceof Service) insertService(job, data, route);
410-
else if (job instanceof Shipment) insertShipment(job, data, route);
409+
else if (job.getJobType().isShipment()) insertShipment(job, data, route);
411410
}
412411

413412
private void insertShipment(Job job, InsertionData data, VehicleRoute route) {

jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BreakScheduling.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public void ruinEnds(Collection<VehicleRoute> routes, Collection<Job> unassigned
8989
}
9090
List<Break> breaks = new ArrayList<>();
9191
for (Job j : unassignedJobs) {
92-
if (j instanceof Break) {
92+
if (j.getJobType().isBreak()) {
9393
breaks.add((Break) j);
9494
}
9595
}

jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/Inserter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public ShipmentInsertionHandler(VehicleRoutingProblem vehicleRoutingProblem) {
103103

104104
@Override
105105
public void handleJobInsertion(Job job, InsertionData iData, VehicleRoute route) {
106-
if (job instanceof Shipment) {
106+
if (job.getJobType().isShipment()) {
107107
List<AbstractActivity> acts = vehicleRoutingProblem.copyAndGetActivities(job);
108108
TourActivity pickupShipment = acts.get(0);
109109
TourActivity deliverShipment = acts.get(1);

jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionCostsCalculatorBuilder.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ public JobInsertionCostsCalculator build() {
260260

261261
private void checkServicesOnly() {
262262
for (Job j : vrp.getJobs().values()) {
263-
if (j instanceof Shipment) {
263+
if (j.getJobType().isShipment()) {
264264
throw new UnsupportedOperationException("currently the 'insert-on-route-level' option is only available for services (i.e. service, pickup, delivery), \n" +
265265
"if you want to deal with shipments switch to option 'local-level' by either setting bestInsertionBuilder.setLocalLevel() or \n"
266266
+ "by omitting the xml-tag '<level forwardLooking=2 memory=1>route</level>' when defining your insertionStrategy in algo-config.xml file");

jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertion.java

+4-6
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
package com.graphhopper.jsprit.core.algorithm.recreate;
2020

2121
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
22-
import com.graphhopper.jsprit.core.problem.job.Break;
2322
import com.graphhopper.jsprit.core.problem.job.Job;
2423
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
2524
import org.slf4j.Logger;
@@ -91,12 +90,11 @@ public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Col
9190
Iterator<Job> jobIterator = unassignedJobs.iterator();
9291
while (jobIterator.hasNext()){
9392
Job job = jobIterator.next();
94-
if(job instanceof Break){
95-
VehicleRoute route = findRoute(routes,job);
96-
if(route == null){
93+
if (job.getJobType().isBreak()) {
94+
VehicleRoute route = findRoute(routes, job);
95+
if (route == null) {
9796
badJobs.add(job);
98-
}
99-
else {
97+
} else {
10098
InsertionData iData = insertionCostsCalculator.getInsertionData(route, job, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, Double.MAX_VALUE);
10199
if (iData instanceof InsertionData.NoInsertionFound) {
102100
badJobs.add(job);

jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrent.java

+4-6
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
package com.graphhopper.jsprit.core.algorithm.recreate;
2020

2121
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
22-
import com.graphhopper.jsprit.core.problem.job.Break;
2322
import com.graphhopper.jsprit.core.problem.job.Job;
2423
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
2524
import org.slf4j.Logger;
@@ -99,12 +98,11 @@ public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Col
9998
Iterator<Job> jobIterator = unassignedJobs.iterator();
10099
while (jobIterator.hasNext()){
101100
Job job = jobIterator.next();
102-
if(job instanceof Break){
103-
VehicleRoute route = findRoute(routes,job);
104-
if(route == null){
101+
if (job.getJobType().isBreak()) {
102+
VehicleRoute route = findRoute(routes, job);
103+
if (route == null) {
105104
badJobs.add(job);
106-
}
107-
else {
105+
} else {
108106
InsertionData iData = insertionCostsCalculator.getInsertionData(route, job, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, Double.MAX_VALUE);
109107
if (iData instanceof InsertionData.NoInsertionFound) {
110108
badJobs.add(job);

jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrentFast.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
2222
import com.graphhopper.jsprit.core.problem.constraint.DependencyType;
23-
import com.graphhopper.jsprit.core.problem.job.Break;
2423
import com.graphhopper.jsprit.core.problem.job.Job;
2524
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
2625
import com.graphhopper.jsprit.core.problem.vehicle.VehicleFleetManager;
@@ -123,12 +122,11 @@ public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Col
123122
Iterator<Job> jobIterator = unassignedJobs.iterator();
124123
while (jobIterator.hasNext()){
125124
Job job = jobIterator.next();
126-
if(job instanceof Break){
125+
if (job.getJobType().isBreak()) {
127126
VehicleRoute route = InsertionDataUpdater.findRoute(routes, job);
128-
if(route == null){
127+
if (route == null) {
129128
badJobs.add(job);
130-
}
131-
else {
129+
} else {
132130
InsertionData iData = insertionCostsCalculator.getInsertionData(route, job, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, Double.MAX_VALUE);
133131
if (iData instanceof InsertionData.NoInsertionFound) {
134132
badJobs.add(job);

jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/state/UpdateLoads.java

+4-7
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,7 @@
2121
import com.graphhopper.jsprit.core.algorithm.recreate.listener.InsertionStartsListener;
2222
import com.graphhopper.jsprit.core.algorithm.recreate.listener.JobInsertedListener;
2323
import com.graphhopper.jsprit.core.problem.Capacity;
24-
import com.graphhopper.jsprit.core.problem.job.Delivery;
2524
import com.graphhopper.jsprit.core.problem.job.Job;
26-
import com.graphhopper.jsprit.core.problem.job.Pickup;
27-
import com.graphhopper.jsprit.core.problem.job.Service;
2825
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
2926
import com.graphhopper.jsprit.core.problem.solution.route.activity.ActivityVisitor;
3027
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
@@ -80,9 +77,9 @@ void insertionStarts(VehicleRoute route) {
8077
Capacity loadAtDepot = Capacity.Builder.newInstance().build();
8178
Capacity loadAtEnd = Capacity.Builder.newInstance().build();
8279
for (Job j : route.getTourActivities().getJobs()) {
83-
if (j instanceof Delivery) {
80+
if (j.getJobType().isDelivery()) {
8481
loadAtDepot = Capacity.addup(loadAtDepot, j.getSize());
85-
} else if (j instanceof Pickup || j instanceof Service) {
82+
} else if (j.getJobType().isPickup() || j.getJobType().isService()) {
8683
loadAtEnd = Capacity.addup(loadAtEnd, j.getSize());
8784
}
8885
}
@@ -99,11 +96,11 @@ public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collec
9996

10097
@Override
10198
public void informJobInserted(Job job2insert, VehicleRoute inRoute, InsertionData insertionData) {
102-
if (job2insert instanceof Delivery) {
99+
if (job2insert.getJobType().isDelivery()) {
103100
Capacity loadAtDepot = stateManager.getRouteState(inRoute, InternalStates.LOAD_AT_BEGINNING, Capacity.class);
104101
if (loadAtDepot == null) loadAtDepot = defaultValue;
105102
stateManager.putTypedInternalRouteState(inRoute, InternalStates.LOAD_AT_BEGINNING, Capacity.addup(loadAtDepot, job2insert.getSize()));
106-
} else if (job2insert instanceof Pickup || job2insert instanceof Service) {
103+
} else if (job2insert.getJobType().isPickup() || job2insert.getJobType().isService()) {
107104
Capacity loadAtEnd = stateManager.getRouteState(inRoute, InternalStates.LOAD_AT_END, Capacity.class);
108105
if (loadAtEnd == null) loadAtEnd = defaultValue;
109106
stateManager.putTypedInternalRouteState(inRoute, InternalStates.LOAD_AT_END, Capacity.addup(loadAtEnd, job2insert.getSize()));

jsprit-core/src/main/java/com/graphhopper/jsprit/core/analysis/SolutionAnalyser.java

+2-5
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,7 @@
2121
import com.graphhopper.jsprit.core.problem.Capacity;
2222
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
2323
import com.graphhopper.jsprit.core.problem.cost.TransportDistance;
24-
import com.graphhopper.jsprit.core.problem.job.Delivery;
2524
import com.graphhopper.jsprit.core.problem.job.Job;
26-
import com.graphhopper.jsprit.core.problem.job.Pickup;
27-
import com.graphhopper.jsprit.core.problem.job.Service;
2825
import com.graphhopper.jsprit.core.problem.solution.SolutionCostCalculator;
2926
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
3027
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
@@ -280,9 +277,9 @@ private void calculateLoadAndActivityStates() {
280277
Capacity loadAtDepot = Capacity.Builder.newInstance().build();
281278
Capacity loadAtEnd = Capacity.Builder.newInstance().build();
282279
for (Job j : route.getTourActivities().getJobs()) {
283-
if (j instanceof Delivery) {
280+
if (j.getJobType().isDelivery()) {
284281
loadAtDepot = Capacity.addup(loadAtDepot, j.getSize());
285-
} else if (j instanceof Pickup || j instanceof Service) {
282+
} else if (j.getJobType().isPickup() || j.getJobType().isService()) {
286283
loadAtEnd = Capacity.addup(loadAtEnd, j.getSize());
287284
}
288285
}

jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/VehicleRoutingProblem.java

+4-5
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,11 @@ public static Builder newInstance() {
100100
@Override
101101
public List<AbstractActivity> createActivities(Job job) {
102102
List<AbstractActivity> acts = new ArrayList<>();
103-
if( job instanceof Break){
103+
if (job.getJobType().isBreak()) {
104104
acts.add(BreakActivity.newInstance((Break) job));
105-
}
106-
else if (job instanceof Service) {
105+
} else if (job instanceof Service) {
107106
acts.add(serviceActivityFactory.createActivity((Service) job));
108-
} else if (job instanceof Shipment) {
107+
} else if (job.getJobType().isShipment()) {
109108
acts.add(shipmentActivityFactory.createPickup((Shipment) job));
110109
acts.add(shipmentActivityFactory.createDelivery((Shipment) job));
111110
}
@@ -218,7 +217,7 @@ public Builder addJob(Job job) {
218217
public Builder addJob(AbstractJob job) {
219218
if (tentativeJobs.containsKey(job.getId()))
220219
throw new IllegalArgumentException("The vehicle routing problem already contains a service or shipment with id " + job.getId() + ". Please make sure you use unique ids for all services and shipments.");
221-
if (!(job instanceof Service || job instanceof Shipment))
220+
if (!(job instanceof Service || job.getJobType().isShipment()))
222221
throw new IllegalArgumentException("Job must be either a service or a shipment.");
223222
tentativeJobs.put(job.getId(), job);
224223
addLocationToTentativeLocations(job);

jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxTimeInVehicleConstraint.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import com.graphhopper.jsprit.core.problem.cost.TransportTime;
2525
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
2626
import com.graphhopper.jsprit.core.problem.job.Job;
27-
import com.graphhopper.jsprit.core.problem.job.Shipment;
2827
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
2928
import com.graphhopper.jsprit.core.problem.solution.route.activity.DeliveryActivity;
3029
import com.graphhopper.jsprit.core.problem.solution.route.activity.End;
@@ -121,7 +120,7 @@ else if(newActIsPickup){
121120
for (Job openJob : openJobsAtNext.keySet()) {
122121
double slack = openJobsAtNext.get(openJob);
123122
double additionalTimeOfNewJob = additionalTimeOfNewAct;
124-
if (openJob instanceof Shipment) {
123+
if (openJob.getJobType().isShipment()) {
125124
Map<Job, Double> openJobsAtNextOfPickup = Collections.emptyMap();
126125
TourActivity nextAfterPickup;
127126
if (iFacts.getAssociatedActivities().size() == 1 && !iFacts.getRoute().isEmpty())

jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/ServiceLoadRouteLevelConstraint.java

+2-5
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@
1919

2020
import com.graphhopper.jsprit.core.algorithm.state.InternalStates;
2121
import com.graphhopper.jsprit.core.problem.Capacity;
22-
import com.graphhopper.jsprit.core.problem.job.Delivery;
23-
import com.graphhopper.jsprit.core.problem.job.Pickup;
24-
import com.graphhopper.jsprit.core.problem.job.Service;
2522
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
2623
import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter;
2724

@@ -53,13 +50,13 @@ public boolean fulfilled(JobInsertionContext insertionContext) {
5350
if (!maxLoadAtRoute.isLessOrEqual(capacityDimensions)) {
5451
return false;
5552
}
56-
if (insertionContext.getJob() instanceof Delivery) {
53+
if (insertionContext.getJob().getJobType().isDelivery()) {
5754
Capacity loadAtDepot = stateManager.getRouteState(insertionContext.getRoute(), InternalStates.LOAD_AT_BEGINNING, Capacity.class);
5855
if (loadAtDepot == null) loadAtDepot = defaultValue;
5956
if (!Capacity.addup(loadAtDepot, insertionContext.getJob().getSize()).isLessOrEqual(capacityDimensions)) {
6057
return false;
6158
}
62-
} else if (insertionContext.getJob() instanceof Pickup || insertionContext.getJob() instanceof Service) {
59+
} else if (insertionContext.getJob().getJobType().isPickup() || insertionContext.getJob().getJobType().isService()) {
6360
Capacity loadAtEnd = stateManager.getRouteState(insertionContext.getRoute(), InternalStates.LOAD_AT_END, Capacity.class);
6461
if (loadAtEnd == null) loadAtEnd = defaultValue;
6562
if (!Capacity.addup(loadAtEnd, insertionContext.getJob().getSize()).isLessOrEqual(capacityDimensions)) {

jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Break.java

+3
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,7 @@ public boolean hasVariableLocation() {
7878
return variableLocation;
7979
}
8080

81+
public Type getJobType() {
82+
return Type.BREAK_SERVICE;
83+
}
8184
}

jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Delivery.java

+4
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,8 @@ public Delivery build() {
7070

7171
}
7272

73+
public Type getJobType() {
74+
return Type.DELIVERY_SERVICE;
75+
}
76+
7377
}

jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Job.java

+38
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,44 @@
3232
*/
3333
public interface Job extends HasId, HasIndex {
3434

35+
enum Type {
36+
SHIPMENT,
37+
SERVICE,
38+
PICKUP_SERVICE,
39+
DELIVERY_SERVICE,
40+
BREAK_SERVICE;
41+
42+
public boolean isShipment() {
43+
return this == SHIPMENT;
44+
}
45+
46+
public boolean isService() {
47+
return !isShipment();
48+
}
49+
50+
public boolean isPickup() {
51+
return this == PICKUP_SERVICE;
52+
}
53+
54+
public boolean isDelivery() {
55+
return this == DELIVERY_SERVICE;
56+
}
57+
58+
public boolean isBreak() {
59+
return this == BREAK_SERVICE;
60+
}
61+
}
62+
63+
// Add default method for type to maintain backward compatibility
64+
default Type getJobType() {
65+
// Default implementation based on class type
66+
if (this instanceof Shipment) return Type.SHIPMENT;
67+
if (this instanceof Pickup) return Type.PICKUP_SERVICE;
68+
if (this instanceof Delivery) return Type.DELIVERY_SERVICE;
69+
if (this instanceof Break) return Type.BREAK_SERVICE;
70+
if (this instanceof Service) return Type.SERVICE;
71+
throw new IllegalStateException("Unknown job type: " + this.getClass());
72+
}
3573

3674
/**
3775
* Returns the unique identifier (id) of a job.

jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Pickup.java

+3
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,7 @@ public Pickup build() {
7171
super(builder);
7272
}
7373

74+
public Type getJobType() {
75+
return Type.PICKUP_SERVICE;
76+
}
7477
}

jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,10 @@ public String getType() {
352352
return type;
353353
}
354354

355+
public Type getJobType() {
356+
return Type.SERVICE;
357+
}
358+
355359
/**
356360
* Returns a string with the service's attributes.
357361
* <p>
@@ -360,7 +364,7 @@ public String getType() {
360364
@Override
361365
public String toString() {
362366
return "[id=" + id + "][name=" + name + "][type=" + type + "][location=" + location
363-
+ "][capacity=" + size + "][serviceTime=" + serviceTime + "][timeWindows="
367+
+ "][capacity=" + size + "][serviceTime=" + serviceTime + "][timeWindows="
364368
+ timeWindows + "]";
365369
}
366370

@@ -429,4 +433,5 @@ public List<Activity> getActivities() {
429433
return activities;
430434
}
431435

436+
432437
}

jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java

+4
Original file line numberDiff line numberDiff line change
@@ -537,4 +537,8 @@ public double getMaxTimeInVehicle() {
537537
public List<Activity> getActivities() {
538538
return activities;
539539
}
540+
541+
public Type getJobType() {
542+
return Type.SHIPMENT;
543+
}
540544
}

0 commit comments

Comments
 (0)