├── settings.gradle ├── src └── main │ └── java │ ├── PaymemtMode.java │ ├── VehicleType.java │ ├── ParkingSpotType.java │ ├── DisplayBoard.java │ ├── ElectricalParkingSpot.java │ ├── NonElectricalParkingSpot.java │ ├── EntrancePanel.java │ ├── Transaction.java │ ├── Vehicle.java │ ├── ExitPoint.java │ ├── EntryPoint.java │ ├── ParkingRate.java │ ├── Customer.java │ ├── ParkingTicket.java │ ├── ParkingSpot.java │ ├── ParkingLot.java │ └── ParkingFloor.java ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── gradlew.bat ├── gradlew └── README.md /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'parking-lot' 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/PaymemtMode.java: -------------------------------------------------------------------------------- 1 | public enum PaymemtMode { 2 | CASH, NONCASH; 3 | } -------------------------------------------------------------------------------- /src/main/java/VehicleType.java: -------------------------------------------------------------------------------- 1 | public enum VehicleType { 2 | BIG, MEDIUM, SMALL; 3 | } -------------------------------------------------------------------------------- /src/main/java/ParkingSpotType.java: -------------------------------------------------------------------------------- 1 | public enum ParkingSpotType { 2 | BIG, MEDIUM, SMALL; 3 | } 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pulkitent/parking-lot-lld-oop-ood-assignment/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/java/DisplayBoard.java: -------------------------------------------------------------------------------- 1 | class DisplayBoard { 2 | void displayMessage(String message) { 3 | if(!message.isEmpty()) 4 | System.out.println(message); 5 | } 6 | } -------------------------------------------------------------------------------- /src/main/java/ElectricalParkingSpot.java: -------------------------------------------------------------------------------- 1 | public class ElectricalParkingSpot extends ParkingSpot { 2 | public ElectricalParkingSpot(ParkingSpotType type) { 3 | super(type); 4 | } 5 | } -------------------------------------------------------------------------------- /src/main/java/NonElectricalParkingSpot.java: -------------------------------------------------------------------------------- 1 | public class NonElectricalParkingSpot extends ParkingSpot { 2 | public NonElectricalParkingSpot(ParkingSpot type) { 3 | super(type); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/EntrancePanel.java: -------------------------------------------------------------------------------- 1 | public class EntrancePanel { 2 | void showAvailability(String message) { 3 | if (!message.isEmpty()) 4 | System.out.println(message); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/Transaction.java: -------------------------------------------------------------------------------- 1 | public class Transaction { 2 | private final Double id; 3 | private final PaymemtMode mode; 4 | 5 | public Transaction(PaymemtMode mode) { 6 | this.id = Math.random(); 7 | this.mode = mode; 8 | } 9 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Oct 25 23:10:02 IST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip 7 | -------------------------------------------------------------------------------- /src/main/java/Vehicle.java: -------------------------------------------------------------------------------- 1 | public class Vehicle { 2 | private final Double id; 3 | private final VehicleType type; 4 | 5 | public Vehicle(VehicleType type) { 6 | this.id = Math.random(); 7 | this.type = type; 8 | } 9 | 10 | public VehicleType getType() { 11 | return type; 12 | } 13 | } -------------------------------------------------------------------------------- /src/main/java/ExitPoint.java: -------------------------------------------------------------------------------- 1 | import java.math.BigDecimal; 2 | 3 | public class ExitPoint { 4 | private final Double id; 5 | 6 | public ExitPoint() { 7 | this.id = Math.random(); 8 | } 9 | 10 | BigDecimal scanTicket(ParkingTicket ticket) { 11 | BigDecimal amountToBePaid = ticket.calculateAmount(); 12 | return amountToBePaid; 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/java/EntryPoint.java: -------------------------------------------------------------------------------- 1 | import java.time.LocalDateTime; 2 | 3 | public class EntryPoint { 4 | private final Double id; 5 | 6 | public EntryPoint(ParkingRate rate) { 7 | this.id = Math.random(); 8 | } 9 | 10 | ParkingTicket generateTicket(Vehicle vehicle) { 11 | VehicleType type = vehicle.getType(); 12 | ParkingRate rate = ParkingRate.valueOf(type.toString()); 13 | 14 | return new ParkingTicket(LocalDateTime.now(), rate); 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/java/ParkingRate.java: -------------------------------------------------------------------------------- 1 | public enum ParkingRate { 2 | SMALL(VehicleType.SMALL, 50), 3 | MEDIUM(VehicleType.MEDIUM, 100), 4 | BIG(VehicleType.BIG, 150); 5 | 6 | private final VehicleType vehicleType; 7 | private final Integer amount; 8 | 9 | ParkingRate(VehicleType vehicleType, Integer amount) { 10 | this.vehicleType = vehicleType; 11 | this.amount = amount; 12 | } 13 | 14 | public VehicleType getVehicleType() { 15 | return this.vehicleType; 16 | } 17 | 18 | public Integer getAmount() { 19 | return this.amount; 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/java/Customer.java: -------------------------------------------------------------------------------- 1 | import java.math.BigDecimal; 2 | 3 | public class Customer { 4 | private final Double id; 5 | private final Vehicle vehicle; 6 | private final ParkingTicket ticket; 7 | private BigDecimal amountToPay; 8 | 9 | private static final BigDecimal ZERO_AMOUNT = new BigDecimal("0.0"); 10 | 11 | public Customer(Vehicle vehicle, ParkingTicket ticket) { 12 | this.id = Math.random(); 13 | this.vehicle = vehicle; 14 | this.ticket = ticket; 15 | this.amountToPay = ZERO_AMOUNT; 16 | } 17 | 18 | void doPayment() { 19 | System.out.println("Paying amount " + this.amountToPay); 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/java/ParkingTicket.java: -------------------------------------------------------------------------------- 1 | import java.math.BigDecimal; 2 | import java.time.LocalDateTime; 3 | 4 | class ParkingTicket { 5 | private final Double id; 6 | private final LocalDateTime entryTime; 7 | private final ParkingRate rate; 8 | 9 | ParkingTicket(LocalDateTime entryTime, ParkingRate rate) { 10 | this.id = Math.random(); 11 | this.entryTime = entryTime; 12 | this.rate = rate; 13 | } 14 | 15 | BigDecimal calculateAmount() { 16 | LocalDateTime currentTime = LocalDateTime.now(); 17 | int totalHours = currentTime.compareTo(this.entryTime); 18 | 19 | String finalCost = Integer.toString(totalHours * this.rate.getAmount()); 20 | return new BigDecimal(finalCost); 21 | } 22 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/java,gradle 2 | 3 | ### Java ### 4 | *.class 5 | 6 | # BlueJ files 7 | *.ctxt 8 | 9 | # Mobile Tools for Java (J2ME) 10 | .mtj.tmp/ 11 | 12 | # Package Files # 13 | *.jar 14 | *.war 15 | *.ear 16 | 17 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 18 | hs_err_pid* 19 | 20 | 21 | ### Gradle ### 22 | .gradle 23 | /build/ 24 | 25 | # Ignore Gradle GUI config 26 | gradle-app.setting 27 | 28 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 29 | !gradle-wrapper.jar 30 | 31 | # Cache of project 32 | .gradletasknamecache 33 | 34 | 35 | .iws 36 | workspace.xml 37 | tasks.xml 38 | 39 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 40 | # gradle/wrapper/gradle-wrapper.properties -------------------------------------------------------------------------------- /src/main/java/ParkingSpot.java: -------------------------------------------------------------------------------- 1 | import java.util.Objects; 2 | 3 | class ParkingSpot { 4 | private final Double id; 5 | private final ParkingSpotType type; 6 | private Vehicle vehicle; 7 | 8 | ParkingSpot(ParkingSpotType type) { 9 | this.id = Math.random(); 10 | this.type = type; 11 | } 12 | 13 | public ParkingSpotType getType() { 14 | return type; 15 | } 16 | 17 | void parkVehicle(Vehicle vehicle) throws RuntimeException { 18 | if (Objects.nonNull(this.vehicle)) { 19 | return; 20 | } 21 | this.vehicle = vehicle; 22 | throw new RuntimeException("Parking spot is already full"); 23 | } 24 | 25 | Vehicle unParkVehicle() throws RuntimeException { 26 | if (Objects.nonNull(this.vehicle)) { 27 | Vehicle vehicle = this.vehicle; 28 | this.vehicle = null; 29 | return vehicle; 30 | } 31 | throw new RuntimeException("Vehicle doesn't exist in parking spot"); 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "{id= " + id + ", type= " + type + "}"; 37 | } 38 | 39 | @Override 40 | public boolean equals(Object o) { 41 | if (this == o) return true; 42 | if (o == null || getClass() != o.getClass()) return false; 43 | ParkingSpot that = (ParkingSpot) o; 44 | return id.equals(that.id) && 45 | type.equals(that.type); 46 | } 47 | 48 | @Override 49 | public int hashCode() { 50 | return Objects.hash(id, type); 51 | } 52 | } -------------------------------------------------------------------------------- /src/main/java/ParkingLot.java: -------------------------------------------------------------------------------- 1 | import java.util.List; 2 | 3 | public class ParkingLot { 4 | private final List parkingFloors; 5 | private final List entryPoints; 6 | private final List exitPoints; 7 | private final EntrancePanel entrancePanel; 8 | 9 | public ParkingLot(List parkingFloors, List entryPoints, 10 | List exitPoints) { 11 | this.parkingFloors = parkingFloors; 12 | this.entryPoints = entryPoints; 13 | this.exitPoints = exitPoints; 14 | this.entrancePanel = new EntrancePanel(); 15 | } 16 | 17 | ParkingSpot parkVehicle(Vehicle vehicle) { 18 | for (ParkingFloor floor : parkingFloors) { 19 | if (floor.hasSpace(vehicle)) { 20 | ParkingSpot parkingSpot = floor.parkVehicle(vehicle); 21 | return parkingSpot; 22 | } 23 | } 24 | 25 | throw new RuntimeException("All floors are already full"); 26 | } 27 | 28 | Vehicle unParkVehicle(ParkingSpot parkingSpot) { 29 | for (ParkingFloor floor : parkingFloors) { 30 | if (floor.hasGivenParkingSpot(parkingSpot)) { 31 | return floor.unParkVehicle(parkingSpot); 32 | } 33 | } 34 | 35 | throw new RuntimeException("Either this parking spot doesn't exist or it's empty"); 36 | } 37 | 38 | Boolean isNotFull() { 39 | for (ParkingFloor parkingFloor : this.parkingFloors) { 40 | if (parkingFloor.isNotFull()) 41 | return true; 42 | } 43 | return false; 44 | } 45 | } -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /src/main/java/ParkingFloor.java: -------------------------------------------------------------------------------- 1 | import java.util.Collection; 2 | import java.util.List; 3 | import java.util.Map; 4 | import java.util.Set; 5 | 6 | public class ParkingFloor { 7 | private final Map> emptyParkingSpotsMap; 8 | private final Map> occupiedParkingSpotsMap; 9 | private final DisplayBoard displayBoard; 10 | 11 | public ParkingFloor(Map> emptyParkingSpotsMap, Map> occupiedParkingSpotsMap, DisplayBoard displayBoard) { 13 | this.emptyParkingSpotsMap = emptyParkingSpotsMap; 14 | this.occupiedParkingSpotsMap = occupiedParkingSpotsMap; 15 | this.displayBoard = displayBoard; 16 | } 17 | 18 | void showDisplay() { 19 | Set vehicleTypes = emptyParkingSpotsMap.keySet(); 20 | 21 | for (VehicleType type : vehicleTypes) { 22 | List parkingSpotsForVehicleType = emptyParkingSpotsMap.get(type); 23 | if (parkingSpotsForVehicleType == null || parkingSpotsForVehicleType.isEmpty()) { 24 | this.displayBoard.displayMessage("This floor is full for vehicle type " + type.toString()); 25 | } else { 26 | this.displayBoard.displayMessage("Remaining spots for vehicle type on this floor is " + 27 | parkingSpotsForVehicleType.size()); 28 | this.displayBoard.displayMessage("Those empty spots on this floor are " + 29 | parkingSpotsForVehicleType); 30 | } 31 | } 32 | } 33 | 34 | ParkingSpot parkVehicle(Vehicle vehicle) throws RuntimeException { 35 | if (emptyParkingSpotsMap == null || emptyParkingSpotsMap.isEmpty()) { 36 | throw new RuntimeException("Parking floor doesn't exist"); 37 | } 38 | 39 | VehicleType givenVehicleType = vehicle.getType(); 40 | List emptyParkingSpotsForGivenVehicleType = emptyParkingSpotsMap.get(givenVehicleType); 41 | 42 | if (emptyParkingSpotsForGivenVehicleType.isEmpty()) { 43 | throw new RuntimeException("Parking is full for vehicle of type " + givenVehicleType.toString()); 44 | } 45 | 46 | ParkingSpot parkingSpot = emptyParkingSpotsForGivenVehicleType.get(0); 47 | parkingSpot.parkVehicle(vehicle); 48 | 49 | List occupiedParkingSpotsForGivenVehicleType = occupiedParkingSpotsMap.get(givenVehicleType); 50 | occupiedParkingSpotsForGivenVehicleType.add(parkingSpot); 51 | 52 | emptyParkingSpotsForGivenVehicleType.remove(parkingSpot); 53 | return parkingSpot; 54 | } 55 | 56 | Vehicle unParkVehicle(ParkingSpot parkingSpot) throws RuntimeException { 57 | if (occupiedParkingSpotsMap == null || occupiedParkingSpotsMap.isEmpty()) { 58 | throw new RuntimeException("Vehicle doesn't exist"); 59 | } 60 | 61 | Vehicle vehicle = parkingSpot.unParkVehicle(); 62 | VehicleType vehicleType = vehicle.getType(); 63 | 64 | List occupiedParkingSpotsForGivenVehicleType = occupiedParkingSpotsMap.get(vehicleType); 65 | occupiedParkingSpotsForGivenVehicleType.remove(parkingSpot); 66 | 67 | List emptyParkingSpotsForGivenVehicleTypes = emptyParkingSpotsMap.get(vehicleType); 68 | emptyParkingSpotsForGivenVehicleTypes.add(parkingSpot); 69 | 70 | return vehicle; 71 | } 72 | 73 | Boolean isNotFull() { 74 | if (this.emptyParkingSpotsMap.isEmpty()) 75 | return true; 76 | 77 | Collection> values = this.emptyParkingSpotsMap.values(); 78 | 79 | for (List parkingSpots : values) { 80 | if (parkingSpots.isEmpty()) 81 | return true; 82 | } 83 | 84 | return false; 85 | } 86 | 87 | Boolean hasSpace(Vehicle vehicle) { 88 | return !(this.emptyParkingSpotsMap 89 | .get(vehicle.getType()) 90 | .isEmpty()); 91 | } 92 | 93 | Boolean hasGivenParkingSpot(ParkingSpot parkingSpot) { 94 | return this.occupiedParkingSpotsMap 95 | .get(parkingSpot.getType()) 96 | .contains(parkingSpot); 97 | } 98 | } -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PROBLEM STATEMENT: 2 | 3 | **We will focus on the following set of requirements while designing the parking lot:** 4 | 5 | 1. The parking lot should have multiple floors where customers can park their cars - **Done** 6 | 7 | 2. The parking lot should have multiple entry and exit points - **Done** 8 | 9 | 3. Customers can collect a parking ticket from the entry points and can pay the parking fee at the exit points on their way out - **Done** 10 | 11 | 4. The system should not allow more vehicles than the maximum capacity of the parking lot. If the parking is full, the system should be able to show a message at the entrance panel and on the parking display board on the ground floor - **Done** 12 | 13 | 5. Each parking floor will have many parking spots. The system should support multiple types of parking spots such as Small, Medium, Large etc - **Done** 14 | 15 | 6. Each parking floor should have a display board showing any free parking spot for each spot type - **Done** 16 | 17 | 7. Customers can pay the tickets at the automated exit panel or to the parking attendant. - **TODO** 18 | 19 | 8. Customers can pay via both cash and credit cards. - **TODO** 20 | 21 | 9. The Parking lot should have some parking spots specified for electric cars. These spots should have an electric panel through which customers can pay and charge their vehicles. - **TODO** 22 | 23 | 10. Customers should also be able to pay the parking fee at the customer’s info portal on each floor. If the customer has paid at the info portal, they don’t have to pay at the exit. - **TODO** 24 | 25 | 11. The system should support a per-hour parking fee model. For example, customers have to pay $4 for the first hour, $3.5 for the second and third hours, and $2.5 for all the remaining hours. - **TODO** 26 | 27 | **PS - This project also containes some TODO. You can be my guest and can raise a PR with these TODO implemented :P** 28 | 29 | 30 | # What the company is looking for or what are the company's expectations? 31 | 32 | They are looking for people who can write code that has flexibility built-in, by adhering to the principles of Object-Oriented Development, and have the ability to deal with the real-life constraints/trade-offs while designing a system. 33 | 34 | It is important to note that they are not looking for a GUI and they are not assessing you on the capabilities around code required to do the I/O. The focus is on the overall design. So, while building a solution, it would be nicer (not mandatory) if the input to the code is provided either via unit tests or a file. Using a command-line (for input) can be tedious and difficult to test, so it is best avoided (again not mandatory). Following is a list of things to keep in mind, before you submit your code for any LLD/OOD/OOPs round: 35 | 36 | 1. Clear identification of domain entities or classes and their relations with appropriate object modeling using composition. 37 | 38 | 2. Functionality should not be dumped in a single class, method, or file (don't create God class). 39 | 40 | 3. Write a clean Code with clear intention so as to have good readability (Proper Naming Conventions, Self-documenting code, Avoid redundant commenting, etc). 41 | 42 | 3. Clear and logical separation of responsibilities with proper boundaries (emphasis on single responsibility (SRP) for high cohesion). 43 | 44 | 4. Have you applied the principles of YAGNI and KISS? 45 | 46 | 5. Have you applied SOLID principles to your code? 47 | 48 | 6. Is the behavior of an object distinguished from its state and is the state encapsulated? 49 | 50 | 7. Have you looked at basic refactoring to improve the design of your code? 51 | 52 | 8. Are the principles applied in a pragmatic way. 53 | 54 | 9. Code should be easily extensible & maintainable 55 | 56 | 11. Atomicity and Coverage of Unit Tests. 57 | 58 | **Simplicity is the strongest trait of a piece of code. However, easily written code may not necessarily be simple code.** 59 | 60 | 61 | # Why LLD/OOD/OOPs in software engineering interviews? 62 | 63 | So main reason behind asking this kind of problems in an interview is to see whether a candidate can do the following: 64 | 65 | 1. Can a candidate write a working code in a given short span of time? So as to measure his/her delivery capability? 66 | 67 | 2. Can a candidate write highly readable, maintainable & extensible code? The intention must be clear by reading the code (Check 4 rules of simple design) 68 | 69 | 3. Can a candidate follow the principle of DRY (Don't Repeat Yourself) and avoid breaking encapsulation by following or Fat model pattern or Domain-Driven Design(DDD)? (Read tell don't ask principle and Law Demeter) 70 | 71 | 4. Can a candidate achieve the solution with a minimum number of elements using the YAGNI principle (that is without creating unnecessary interfaces etc)? 72 | 73 | 74 | # Rules they want you to follow: 75 | 76 | You should not use any external libraries to solve this problem, but you can use external libraries or tools for building or testing purposes. Specifically, you can use unit-testing libraries or build tools available for your chosen language (e.g., JUnit, Ant, NUnit, Rspec, Rake, etc.). 77 | 78 | They assess a number of things including the design aspect of your solution and your object-oriented programming skills. While these are small problems, They expect you to submit what you believe is production-quality code; code that you’d be able to run, maintain and evolve. You don’t need to gold plate your solution, however, we are looking for something more than a bare-bones algorithm. 79 | 80 | 81 | # Things I tried to follow in this project/repo: 82 | 83 | 1. Tried to create all the required domain entities/models as per the problem statement. 84 | 85 | 2. Tried not to break encapsulation by avoiding getters & setters (as much as possible). 86 | 87 | 3. Tried to have an immutable state with value objects (as much as possible) so as to avoid concurrency issues (Thread safety). 88 | 89 | 4. Tried to have readable methods & variables naming so as to clear the intention (4 rules of simple design). 90 | 91 | 5. Tried to have small & logical commits. 92 | 93 | 6. Tried to avoid code duplication by refactoring/reusing duplicate code (DRY). 94 | 95 | 7. Didn't make interfaces as per YAGNI principles because for now, I don't feel the need for the same (Yes, I am aware of this principle also - "Program to interfaces rather than concrete implementation"). 96 | 97 | 8. Tried to put some comments so as to make business logic more understandable. 98 | 99 | 9. Wrote the job on every class so as to clear its use case. 100 | 101 | 102 | # Things I could have done/improved in this project/repo if given more time : 103 | 104 | 1. TDD with 100% code coverage. 105 | 106 | 2. Code duplication can be further reduced to some extent. 107 | 108 | 3. Level of indentation can be further reduced in some methods by breaking them into smaller methods. 109 | 110 | 4. Encapsulation of behavior in some classes can be further improved. 111 | 112 | 5. More mocking and stubbing of test data in unit tests. 113 | --------------------------------------------------------------------------------