From 8860bfcbc0b10b5c5fd1449155551175ea49731c Mon Sep 17 00:00:00 2001 From: Xavier Fontanet Date: Fri, 5 Jul 2024 17:17:30 +0200 Subject: [PATCH] sacrify type safety to obtain independent deployability when a command is added (now the api module doesn't need to be recompiled+redeployed) --- .../marsrover/api/AccelerometeredRover.java | 7 +++ .../marsrover/api/ConsciousRover.java | 4 ++ .../marsrover/api/LocateableRover.java | 2 +- .../codingtests/marsrover/api/RiderRover.java | 3 +- .../marsrover/api/RotableRiderRover.java | 2 +- .../marsrover/api/RotableRover.java | 2 +- .../codingtests/marsrover/api/Rover.java | 4 ++ .../marsrover/api/commands/RoverCommand.java | 1 - .../api/commands/RoverCommandFactory.java | 8 ++-- .../RotableRiderRoverCommandFactory.java | 45 +++++++++++++++++++ .../commands/RoverCommandFactoryImpl.java | 31 ------------- rover-commands/src/main/java/module-info.java | 4 +- .../GivenMarsRoverDeployedOnMarsMap.java | 3 +- ...AndMoveCommandsOnDeployedRoverWithMap.java | 12 +++-- 14 files changed, 78 insertions(+), 50 deletions(-) create mode 100644 rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/AccelerometeredRover.java create mode 100644 rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/ConsciousRover.java create mode 100644 rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/Rover.java create mode 100644 rover-commands/src/main/java/cat/hack3/codingtests/marsrover/commands/RotableRiderRoverCommandFactory.java delete mode 100644 rover-commands/src/main/java/cat/hack3/codingtests/marsrover/commands/RoverCommandFactoryImpl.java diff --git a/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/AccelerometeredRover.java b/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/AccelerometeredRover.java new file mode 100644 index 0000000..122be9a --- /dev/null +++ b/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/AccelerometeredRover.java @@ -0,0 +1,7 @@ +package cat.hack3.codingtests.marsrover.api; + +import cat.hack3.codingtests.marsrover.api.cartography.Direction; + +public interface AccelerometeredRover extends Rover{ + Direction getCurrentDirection(); +} diff --git a/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/ConsciousRover.java b/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/ConsciousRover.java new file mode 100644 index 0000000..cb7426c --- /dev/null +++ b/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/ConsciousRover.java @@ -0,0 +1,4 @@ +package cat.hack3.codingtests.marsrover.api; + +public interface ConsciousRover extends AccelerometeredRover, LocateableRover{ +} diff --git a/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/LocateableRover.java b/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/LocateableRover.java index ae33aff..84668fb 100644 --- a/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/LocateableRover.java +++ b/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/LocateableRover.java @@ -2,6 +2,6 @@ package cat.hack3.codingtests.marsrover.api; import cat.hack3.codingtests.marsrover.api.cartography.Coordinates; -public interface LocateableRover { +public interface LocateableRover extends Rover{ Coordinates getCurrentCoordinates(); } diff --git a/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/RiderRover.java b/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/RiderRover.java index 5763295..ec2d059 100644 --- a/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/RiderRover.java +++ b/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/RiderRover.java @@ -2,7 +2,6 @@ package cat.hack3.codingtests.marsrover.api; import cat.hack3.codingtests.marsrover.api.cartography.Direction; -public interface RiderRover { +public interface RiderRover extends AccelerometeredRover{ void moveTowards(Direction direction); - Direction getCurrentDirection(); } diff --git a/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/RotableRiderRover.java b/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/RotableRiderRover.java index e6dd80d..f0a5761 100644 --- a/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/RotableRiderRover.java +++ b/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/RotableRiderRover.java @@ -3,7 +3,7 @@ package cat.hack3.codingtests.marsrover.api; import cat.hack3.codingtests.marsrover.api.cartography.Direction; import cat.hack3.codingtests.marsrover.api.cartography.PlanetMap; -public interface RotableRiderRover extends RotableRover, RiderRover, LocateableRover { +public interface RotableRiderRover extends RotableRover, RiderRover, ConsciousRover { interface Provider { RotableRiderRover provideWith(PlanetMap map, Direction startingDirection); diff --git a/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/RotableRover.java b/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/RotableRover.java index d493811..21d3744 100644 --- a/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/RotableRover.java +++ b/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/RotableRover.java @@ -1,6 +1,6 @@ package cat.hack3.codingtests.marsrover.api; -public interface RotableRover { +public interface RotableRover extends Rover{ enum Rotation {LEFT, RIGHT} void rotateTowards(Rotation rotation); diff --git a/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/Rover.java b/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/Rover.java new file mode 100644 index 0000000..b05c40b --- /dev/null +++ b/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/Rover.java @@ -0,0 +1,4 @@ +package cat.hack3.codingtests.marsrover.api; + +public interface Rover { +} diff --git a/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/commands/RoverCommand.java b/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/commands/RoverCommand.java index 12d2fff..8e8bb7b 100644 --- a/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/commands/RoverCommand.java +++ b/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/commands/RoverCommand.java @@ -1,7 +1,6 @@ package cat.hack3.codingtests.marsrover.api.commands; public interface RoverCommand { - enum Type {MOVE_FORWARD, MOVE_BACKWARDS, TURN_LEFT, TURN_RIGHT} void execute(); } diff --git a/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/commands/RoverCommandFactory.java b/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/commands/RoverCommandFactory.java index 376eff8..c6cc917 100644 --- a/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/commands/RoverCommandFactory.java +++ b/rover-api/src/main/java/cat/hack3/codingtests/marsrover/api/commands/RoverCommandFactory.java @@ -1,11 +1,13 @@ package cat.hack3.codingtests.marsrover.api.commands; -import cat.hack3.codingtests.marsrover.api.RotableRiderRover; +import cat.hack3.codingtests.marsrover.api.Rover; public interface RoverCommandFactory { - RoverCommand create(RoverCommand.Type type); + RoverCommand create(String commandName) throws InvalidCommandNameProvided; interface Provider { - RoverCommandFactory provideWith(RotableRiderRover rover); + RoverCommandFactory provideWith(Rover rover); } + + class InvalidCommandNameProvided extends RuntimeException{} } diff --git a/rover-commands/src/main/java/cat/hack3/codingtests/marsrover/commands/RotableRiderRoverCommandFactory.java b/rover-commands/src/main/java/cat/hack3/codingtests/marsrover/commands/RotableRiderRoverCommandFactory.java new file mode 100644 index 0000000..485f89d --- /dev/null +++ b/rover-commands/src/main/java/cat/hack3/codingtests/marsrover/commands/RotableRiderRoverCommandFactory.java @@ -0,0 +1,45 @@ +package cat.hack3.codingtests.marsrover.commands; + + +import cat.hack3.codingtests.marsrover.api.RotableRiderRover; +import cat.hack3.codingtests.marsrover.api.Rover; +import cat.hack3.codingtests.marsrover.api.commands.RoverCommand; +import cat.hack3.codingtests.marsrover.api.commands.RoverCommandFactory; + +import java.util.Optional; + +public class RotableRiderRoverCommandFactory implements RoverCommandFactory { + enum RoverCommandType {MOVE_FORWARD, MOVE_BACKWARDS, TURN_LEFT, TURN_RIGHT} + private final RotableRiderRover rover; + + public static class Provider implements RoverCommandFactory.Provider { + @Override + public RoverCommandFactory provideWith(Rover rover) { + return new RotableRiderRoverCommandFactory((RotableRiderRover) rover); + } + } + + private RotableRiderRoverCommandFactory(RotableRiderRover rover) { + this.rover = rover; + } + + @Override + public RoverCommand create(String commandName) { + var commandType = tryResolvingCommandTypeFrom(commandName) + .orElseThrow(InvalidCommandNameProvided::new); + return switch (commandType) { + case MOVE_FORWARD -> new MoveForwardCommand(rover); + case MOVE_BACKWARDS -> new MoveBackwardsCommand(rover); + case TURN_LEFT -> new TurnLeftCommand(rover); + case TURN_RIGHT -> new TurnRightCommand(rover); + }; + } + + private Optional tryResolvingCommandTypeFrom(String commandName) { + try { + return Optional.of(RoverCommandType.valueOf(commandName)); + } catch (IllegalArgumentException e) { + return Optional.empty(); + } + } +} diff --git a/rover-commands/src/main/java/cat/hack3/codingtests/marsrover/commands/RoverCommandFactoryImpl.java b/rover-commands/src/main/java/cat/hack3/codingtests/marsrover/commands/RoverCommandFactoryImpl.java deleted file mode 100644 index 167dca3..0000000 --- a/rover-commands/src/main/java/cat/hack3/codingtests/marsrover/commands/RoverCommandFactoryImpl.java +++ /dev/null @@ -1,31 +0,0 @@ -package cat.hack3.codingtests.marsrover.commands; - - -import cat.hack3.codingtests.marsrover.api.RotableRiderRover; -import cat.hack3.codingtests.marsrover.api.commands.RoverCommand; -import cat.hack3.codingtests.marsrover.api.commands.RoverCommandFactory; - -public class RoverCommandFactoryImpl implements RoverCommandFactory { - private final RotableRiderRover rover; - - public static class Provider implements RoverCommandFactory.Provider { - @Override - public RoverCommandFactory provideWith(RotableRiderRover rover) { - return new RoverCommandFactoryImpl(rover); - } - } - - private RoverCommandFactoryImpl(RotableRiderRover rover) { - this.rover = rover; - } - - @Override - public RoverCommand create(RoverCommand.Type type) { - return switch (type) { - case MOVE_FORWARD -> new MoveForwardCommand(rover); - case MOVE_BACKWARDS -> new MoveBackwardsCommand(rover); - case TURN_LEFT -> new TurnLeftCommand(rover); - case TURN_RIGHT -> new TurnRightCommand(rover); - }; - } -} diff --git a/rover-commands/src/main/java/module-info.java b/rover-commands/src/main/java/module-info.java index d7b0e81..d59ab5e 100644 --- a/rover-commands/src/main/java/module-info.java +++ b/rover-commands/src/main/java/module-info.java @@ -1,9 +1,9 @@ import cat.hack3.codingtests.marsrover.api.commands.RoverCommandFactory; -import cat.hack3.codingtests.marsrover.commands.RoverCommandFactoryImpl; +import cat.hack3.codingtests.marsrover.commands.RotableRiderRoverCommandFactory; module rover.commands { requires rover.api; provides RoverCommandFactory.Provider - with RoverCommandFactoryImpl.Provider; + with RotableRiderRoverCommandFactory.Provider; } \ No newline at end of file diff --git a/tests-suite/src/test/java/cat/hack3/codingtests/marsrover/test/context/GivenMarsRoverDeployedOnMarsMap.java b/tests-suite/src/test/java/cat/hack3/codingtests/marsrover/test/context/GivenMarsRoverDeployedOnMarsMap.java index 70c3a05..fd79f76 100644 --- a/tests-suite/src/test/java/cat/hack3/codingtests/marsrover/test/context/GivenMarsRoverDeployedOnMarsMap.java +++ b/tests-suite/src/test/java/cat/hack3/codingtests/marsrover/test/context/GivenMarsRoverDeployedOnMarsMap.java @@ -1,5 +1,6 @@ package cat.hack3.codingtests.marsrover.test.context; +import cat.hack3.codingtests.marsrover.api.ConsciousRover; import cat.hack3.codingtests.marsrover.api.RotableRiderRover; import cat.hack3.codingtests.marsrover.api.cartography.Direction; @@ -8,7 +9,7 @@ import static cat.hack3.codingtests.marsrover.api.cartography.Direction.SOUTH; public abstract class GivenMarsRoverDeployedOnMarsMap extends GivenMarsMapSquaredWithInitialCoordinates{ static final Direction STARTING_DIRECTION = SOUTH; - protected RotableRiderRover rover; + protected ConsciousRover rover; public void setUp() { super.setUp(); diff --git a/tests-suite/src/test/java/cat/hack3/codingtests/marsrover/test/context/GivenRotableAndMoveCommandsOnDeployedRoverWithMap.java b/tests-suite/src/test/java/cat/hack3/codingtests/marsrover/test/context/GivenRotableAndMoveCommandsOnDeployedRoverWithMap.java index 66ce38a..fd3dd16 100644 --- a/tests-suite/src/test/java/cat/hack3/codingtests/marsrover/test/context/GivenRotableAndMoveCommandsOnDeployedRoverWithMap.java +++ b/tests-suite/src/test/java/cat/hack3/codingtests/marsrover/test/context/GivenRotableAndMoveCommandsOnDeployedRoverWithMap.java @@ -3,8 +3,6 @@ package cat.hack3.codingtests.marsrover.test.context; import cat.hack3.codingtests.marsrover.api.commands.RoverCommand; import cat.hack3.codingtests.marsrover.api.commands.RoverCommandFactory; -import static cat.hack3.codingtests.marsrover.api.commands.RoverCommand.Type.*; - public class GivenRotableAndMoveCommandsOnDeployedRoverWithMap extends GivenMarsRoverDeployedOnMarsMap { public static final Class COMMAND_FACTORY_PROVIDER = RoverCommandFactory.Provider.class; @@ -15,12 +13,12 @@ public class GivenRotableAndMoveCommandsOnDeployedRoverWithMap extends GivenMars public void setUp() { super.setUp(); - var commandFactory = getImplProviderOf(COMMAND_FACTORY_PROVIDER) + RoverCommandFactory commandFactory = getImplProviderOf(COMMAND_FACTORY_PROVIDER) .provideWith(rover); - moveForwardCommand = commandFactory.create(MOVE_FORWARD); - moveBackwardsCommand = commandFactory.create(MOVE_BACKWARDS); - turnLeftCommand = commandFactory.create(TURN_LEFT); - turnRightCommand = commandFactory.create(TURN_RIGHT); + moveForwardCommand = commandFactory.create("MOVE_FORWARD"); + moveBackwardsCommand = commandFactory.create("MOVE_BACKWARDS"); + turnLeftCommand = commandFactory.create("TURN_LEFT"); + turnRightCommand = commandFactory.create("TURN_RIGHT"); } }