Skip to content

Commit d50c4c4

Browse files
committed
Refactor: Apply SRP to Railway Reservation System
Decompose the monolithic 'reservation.java' class into multiple, more focused classes to adhere to the Single Responsibility Principle (SRP). This refactoring aims to improve modularity, testability, and maintainability of the codebase. Key changes include: - **Feat: Introduce Passenger entity class** Created `Passenger.java` to encapsulate all data related to a single passenger (e.g., number, name, age, phone, ticket class). This replaces the multiple parallel arrays previously used. - **Feat: Implement TicketService for business logic** Created `TicketService.java` to handle all core business logic concerning ticket operations. This includes: - Ticket booking and availability checks. - Ticket cancellation and refund calculations. - Passenger search functionality. - Management of ticket counts per class. - **Feat: Develop ConsoleUI for user interaction** Created `ConsoleUI.java` to manage all console-based input and output. This class is now solely responsible for: - Displaying menus and application headings. - Gathering user input for various operations. - Presenting information, results, and error messages to the user. - **Feat: Create ReservationApplication for orchestration** Introduced `ReservationApplication.java` to act as the main application driver. It initializes and coordinates the `ConsoleUI` and `TicketService` components, and manages the main application loop and control flow. - **Refactor: Remove original 'reservation.java' class** The responsibilities of the old `reservation.java` class have been distributed among the new classes, making it obsolete. This restructuring leads to a more organized codebase where each class has a clear and single purpose, making future development and maintenance significantly easier.
1 parent 2ce919b commit d50c4c4

File tree

5 files changed

+509
-227
lines changed

5 files changed

+509
-227
lines changed

Train Reservation/ConsoleUI.java

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
import java.io.BufferedReader;
2+
import java.io.InputStreamReader;
3+
import java.io.IOException;
4+
import java.util.List;
5+
import java.util.Optional;
6+
7+
// Responsibility: To handle all console-based user interaction (input and output).
8+
public class ConsoleUI {
9+
private BufferedReader reader;
10+
11+
public ConsoleUI() {
12+
this.reader = new BufferedReader(new InputStreamReader(System.in));
13+
}
14+
15+
public void displayHeading() {
16+
System.out.println("#########################################################");
17+
System.out.println("*********Railway Reservation For Kabul Express***********");
18+
System.out.println("#########################################################");
19+
}
20+
21+
public int displayMenuAndGetChoice() throws IOException {
22+
System.out.println("\n1. Book ticket");
23+
System.out.println("2. Cancel ticket");
24+
System.out.println("3. Search passenger");
25+
System.out.println("4. Reservation chart");
26+
System.out.println("5. Display unbooked tickets");
27+
System.out.println("6. Exit");
28+
System.out.print("Please enter your choice: ");
29+
try {
30+
return Integer.parseInt(reader.readLine());
31+
} catch (NumberFormatException e) {
32+
return -1; // Invalid choice marker
33+
}
34+
}
35+
36+
public int getTicketClassChoice() throws IOException {
37+
System.out.println("Please enter the class of ticket:");
38+
System.out.println("1. AC\t 2. First\t 3. Sleeper\t");
39+
System.out.print("Enter class choice: ");
40+
try {
41+
return Integer.parseInt(reader.readLine());
42+
} catch (NumberFormatException e) {
43+
return -1; // Invalid class
44+
}
45+
}
46+
47+
public int getNumberOfTickets() throws IOException {
48+
System.out.print("Please enter no. of tickets: ");
49+
try {
50+
return Integer.parseInt(reader.readLine());
51+
} catch (NumberFormatException e) {
52+
return 0; // Invalid number
53+
}
54+
}
55+
56+
public String getPassengerName() throws IOException {
57+
System.out.print("Please enter your name: ");
58+
return reader.readLine();
59+
}
60+
61+
public int getPassengerAge() throws IOException {
62+
System.out.print("Please enter your age: ");
63+
try {
64+
return Integer.parseInt(reader.readLine());
65+
} catch (NumberFormatException e) {
66+
return -1; // Invalid age
67+
}
68+
}
69+
70+
public String getPassengerPhoneNumber() throws IOException {
71+
System.out.print("Please enter your phone number: ");
72+
return reader.readLine();
73+
}
74+
75+
public void displayBookingSuccess(Passenger passenger, double price) {
76+
System.out.println("Ticket successfully booked for passenger no: " + passenger.getPassengerNumber());
77+
System.out.println("Please pay Rs." + price);
78+
}
79+
80+
public void displayBookingFailureNoAvailability() {
81+
System.out.println("Sorry, not enough tickets available in the selected class.");
82+
}
83+
84+
public int getPassengerNumberForCancelOrSearch(String action) throws IOException {
85+
System.out.print("Please enter passenger no. to " + action + ": ");
86+
try {
87+
return Integer.parseInt(reader.readLine());
88+
} catch (NumberFormatException e) {
89+
return -1; // Invalid number
90+
}
91+
}
92+
93+
public void displayCancellationSuccess(double refundAmount) {
94+
System.out.println("Ticket successfully cancelled.");
95+
System.out.println("Please collect refund of Rs." + refundAmount);
96+
}
97+
98+
public void displayCancellationFailure() {
99+
System.out.println("Passenger not found. Cancellation failed.");
100+
}
101+
102+
public void displayPassengerDetails(Optional<Passenger> passengerOpt) {
103+
if (passengerOpt.isPresent()) {
104+
Passenger p = passengerOpt.get();
105+
System.out.println("Detail found:");
106+
System.out.println("Passenger no. = " + p.getPassengerNumber());
107+
System.out.println("Name = " + p.getName());
108+
System.out.println("Class = " + getClassString(p.getTicketClass()));
109+
System.out.println("Phone no. = " + p.getPhoneNumber());
110+
System.out.println("Age = " + p.getAge());
111+
} else {
112+
System.out.println("No such passenger.");
113+
}
114+
}
115+
116+
private String getClassString(int classCode) {
117+
switch (classCode) {
118+
case 1: return "AC";
119+
case 2: return "First";
120+
case 3: return "Sleeper";
121+
default: return "Unknown";
122+
}
123+
}
124+
125+
public void displayReservationChart(List<Passenger> acPassengers, List<Passenger> firstPassengers, List<Passenger> sleeperPassengers) {
126+
System.out.println("\n--- Reservation Chart ---");
127+
System.out.println("Passenger list in AC class");
128+
System.out.println("PNO \t Name \t\t Age \t Phone No.");
129+
acPassengers.forEach(System.out::println);
130+
131+
System.out.println("\nPassenger list in First class");
132+
System.out.println("PNO \t Name \t\t Age \t Phone No.");
133+
firstPassengers.forEach(System.out::println);
134+
135+
System.out.println("\nPassenger list in Sleeper class");
136+
System.out.println("PNO \t Name \t\t Age \t Phone No.");
137+
sleeperPassengers.forEach(System.out::println);
138+
}
139+
140+
public void displayUnbookedTickets(int ac, int first, int sleeper) {
141+
System.out.println("\n--- Unbooked Tickets Status ---");
142+
System.out.println("AC class: " + ac);
143+
System.out.println("First class: " + first);
144+
System.out.println("Sleeper class: " + sleeper);
145+
}
146+
147+
public void displayExitMessage() {
148+
System.out.println("\n&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
149+
System.out.println("Project done by: Nikhil Falke (Refactored Version)");
150+
System.out.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
151+
System.out.println("Exiting application...");
152+
}
153+
154+
public void displayInvalidChoice() {
155+
System.out.println("Invalid choice. Please try again.");
156+
}
157+
158+
public void waitForEnter() {
159+
System.out.println("\nPress Enter to continue...");
160+
try {
161+
reader.readLine();
162+
} catch (IOException e) {
163+
// Ignore
164+
}
165+
}
166+
167+
public void clearScreen() {
168+
// This is a simple way to simulate screen clearing in console.
169+
// Might not work perfectly on all terminals.
170+
System.out.print("\033[H\033[2J");
171+
System.out.flush();
172+
}
173+
}

Train Reservation/Passenger.java

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Responsibility: To hold data for a single passenger.
2+
3+
public class Passenger {
4+
private int passengerNumber;
5+
private String name;
6+
private String phoneNumber;
7+
private int age;
8+
private int ticketClass; // 1: AC, 2: First, 3: Sleeper
9+
10+
public Passenger(int passengerNumber, String name, String phoneNumber, int age, int ticketClass) {
11+
this.passengerNumber = passengerNumber;
12+
this.name = name;
13+
this.phoneNumber = phoneNumber;
14+
this.age = age;
15+
this.ticketClass = ticketClass;
16+
}
17+
18+
// Getters
19+
public int getPassengerNumber() {
20+
return passengerNumber;
21+
}
22+
23+
public String getName() {
24+
return name;
25+
}
26+
27+
public String getPhoneNumber() {
28+
return phoneNumber;
29+
}
30+
31+
public int getAge() {
32+
return age;
33+
}
34+
35+
public int getTicketClass() {
36+
return ticketClass;
37+
}
38+
39+
// Setters (if mutable instances are desired, otherwise make it immutable)
40+
public void setName(String name) {
41+
this.name = name;
42+
}
43+
44+
public void setPhoneNumber(String phoneNumber) {
45+
this.phoneNumber = phoneNumber;
46+
}
47+
48+
public void setAge(int age) {
49+
this.age = age;
50+
}
51+
52+
public void setTicketClass(int ticketClass) {
53+
this.ticketClass = ticketClass;
54+
}
55+
56+
@Override
57+
public String toString() {
58+
return passengerNumber + "\t" + name + "\t\t" + age + "\t" + phoneNumber;
59+
}
60+
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import java.io.IOException;
2+
import java.util.List;
3+
import java.util.Optional;
4+
5+
// Responsibility: To orchestrate the application flow, coordinating
6+
// between the UI and the service layer. Contains the main method.
7+
public class ReservationApplication {
8+
private ConsoleUI ui;
9+
private TicketService ticketService;
10+
11+
public ReservationApplication() {
12+
this.ui = new ConsoleUI();
13+
// Initialize with some capacity
14+
this.ticketService = new TicketService(75, 125, 175);
15+
}
16+
17+
public void run() {
18+
int choice;
19+
try {
20+
do {
21+
ui.clearScreen();
22+
ui.displayHeading();
23+
choice = ui.displayMenuAndGetChoice();
24+
25+
switch (choice) {
26+
case 1:
27+
handleBookTicket();
28+
break;
29+
case 2:
30+
handleCancelTicket();
31+
break;
32+
case 3:
33+
handleSearchPassenger();
34+
break;
35+
case 4:
36+
handleDisplayReservationChart();
37+
break;
38+
case 5:
39+
handleDisplayUnbookedTickets();
40+
break;
41+
case 6:
42+
ui.displayExitMessage();
43+
break;
44+
default:
45+
ui.displayInvalidChoice();
46+
}
47+
if (choice != 6) {
48+
ui.waitForEnter();
49+
}
50+
} while (choice != 6);
51+
} catch (IOException e) {
52+
System.err.println("An I/O error occurred: " + e.getMessage());
53+
}
54+
}
55+
56+
private void handleBookTicket() throws IOException {
57+
int ticketClass = ui.getTicketClassChoice();
58+
if (ticketClass < 1 || ticketClass > 3) {
59+
ui.displayInvalidChoice();
60+
return;
61+
}
62+
int numTickets = ui.getNumberOfTickets();
63+
if (numTickets <= 0) {
64+
System.out.println("Number of tickets must be positive.");
65+
return;
66+
}
67+
68+
if (ticketService.checkAvailability(ticketClass, numTickets)) {
69+
String name = ui.getPassengerName();
70+
int age = ui.getPassengerAge();
71+
if (age <=0) {
72+
System.out.println("Invalid age.");
73+
return;
74+
}
75+
String phone = ui.getPassengerPhoneNumber();
76+
77+
Optional<Passenger> bookedPassenger = ticketService.bookTicket(name, phone, age, ticketClass, numTickets);
78+
if(bookedPassenger.isPresent()){
79+
double price = ticketService.calculatePrice(ticketClass, numTickets);
80+
ui.displayBookingSuccess(bookedPassenger.get(), price);
81+
} else {
82+
// This case should ideally not be reached if checkAvailability was true,
83+
// but good for defensive programming or more complex scenarios.
84+
System.out.println("Booking failed unexpectedly.");
85+
}
86+
} else {
87+
ui.displayBookingFailureNoAvailability();
88+
}
89+
}
90+
91+
private void handleCancelTicket() throws IOException {
92+
int passengerNum = ui.getPassengerNumberForCancelOrSearch("cancel");
93+
if(passengerNum == -1){
94+
System.out.println("Invalid passenger number format.");
95+
return;
96+
}
97+
Optional<Passenger> passengerOpt = ticketService.findPassengerByNumber(passengerNum);
98+
99+
if (passengerOpt.isPresent()) {
100+
boolean cancelled = ticketService.cancelTicket(passengerNum);
101+
if (cancelled) {
102+
double refund = ticketService.calculateRefund(passengerOpt.get().getTicketClass());
103+
ui.displayCancellationSuccess(refund);
104+
} else {
105+
// Should not happen if passenger was found, but for safety:
106+
ui.displayCancellationFailure();
107+
}
108+
} else {
109+
ui.displayCancellationFailure();
110+
}
111+
}
112+
113+
private void handleSearchPassenger() throws IOException {
114+
int passengerNum = ui.getPassengerNumberForCancelOrSearch("search");
115+
if(passengerNum == -1){
116+
System.out.println("Invalid passenger number format.");
117+
return;
118+
}
119+
Optional<Passenger> passenger = ticketService.findPassengerByNumber(passengerNum);
120+
ui.displayPassengerDetails(passenger);
121+
}
122+
123+
private void handleDisplayReservationChart() {
124+
List<Passenger> acPassengers = ticketService.getPassengersByClass(1);
125+
List<Passenger> firstPassengers = ticketService.getPassengersByClass(2);
126+
List<Passenger> sleeperPassengers = ticketService.getPassengersByClass(3);
127+
ui.displayReservationChart(acPassengers, firstPassengers, sleeperPassengers);
128+
}
129+
130+
private void handleDisplayUnbookedTickets() {
131+
ui.displayUnbookedTickets(
132+
ticketService.getRemainingAcTickets(),
133+
ticketService.getRemainingFirstClassTickets(),
134+
ticketService.getRemainingSleeperTickets()
135+
);
136+
}
137+
138+
public static void main(String[] args) {
139+
ReservationApplication app = new ReservationApplication();
140+
app.run();
141+
}
142+
}

0 commit comments

Comments
 (0)