오늘의 과정 목록
- 주차장 관리 시스템 코드 작성
- 객체 지향 프로그래밍 / SOLID 원칙
주차장 관리 시스템
필요한 코드)
주차 등록
주차 확인
출차
관리 데이터)
차량번호, 차종, 주차공간, 층수, 입차시간, 출차시간, 요금, 차량수
층 수 : 10층 | 층 당 : 30대
경차 : 1000원 | 중대형 : 1500원 | SUV : 2000원
기본 베이스
public class ParkingApplication {
public static void main(String[] arge) {
// 주차 공간
/*
2차원 배열을 사용한다.
10층에 각 30개의 공간 배열.
주차가 되어 있는가 안 되어 있는가
- true와 false로 판단하기 위해 boolean을 사용.
- true면 자리가 없고. false면 주차 공간이 있음.
*/
boolean[][] parkingSpaces = new boolean[10][30];
// 주차한 차량 번호
String[][] registerNumberes = new String[10][30];
// 입차 시간
int[][] getInTimes = new int[10][30];
// 차종 (지정할 차 종류가 정해져 있으므로 인트로 해도 무방함)
String[][] types = new String[10][30];
2차원 배열
기능 구현
int totalFreeSpace = 0; // 하나의 데이터 공간이기 때문에 일반 변수로 둠.
// 2차원 for문이기 때문에 두 번 for문을 쓰게 됨. 3차원이면 3번.
for(boolean[] layer: parkingSpaces) {
for(boolean space: layer) {
if(!space) totalFreeSpace++;
}
}
System.out.println("여유 공간 : " + totalFreeSpace);
/*
출력 결과)
여유 공간 : 300
*/
int[] layerFreeSpaces = new int[10];
// for(boolean[] layer: parkingSpaces)
// -> 몇 번째 층인지 알 수 없기 때문에 일반 for문을 사용해야 한다.
for(int layer = 0; layer < parkingSpaces.length; layer++) {
// parkingSpaces에 있는 layer 인덱스를 지정한다. 즉 parkingSpaces[layer]은 하나의 배열
for(boolean space: parkingSpaces[layer]) {
if(!space) layerFreeSpaces[layer]++;
}
}
for(int layer = 0; layer < layerFreeSpaces.length; layer++) {
System.out.println(layer + 1 + "층 여유 공간 : " + layerFreeSpaces[layer]);
}
Scanner scanner = new Scanner(System.in);
/*
출력 결과)
1층 여유 공간 : 30
2층 여유 공간 : 30
3층 여유 공간 : 30
4층 여유 공간 : 30
5층 여유 공간 : 30
6층 여유 공간 : 30
7층 여유 공간 : 30
8층 여유 공간 : 30
9층 여유 공간 : 30
10층 여유 공간 : 30
*/
입차 (차량번호, 차종, 입차시간, 주차할 공간)
System.out.print("차량 번호 : ");
String registerNumber = scanner.nextLine();
System.out.print("차종 : ");
String type = scanner.nextLine();
System.out.print("입차 시간 (0 ~ 24) : ");
int getInTime = scanner.nextInt();
System.out.print("주차 층 (0 ~ 9) : ");
int parkingLayer = scanner.nextInt();
System.out.print("주차 공간 (0 ~ 29) : ");
int parkingSpace = scanner.nextInt();
/*
출력 결과)
차량 번호 : 가123 12
차종 : 경차
입차 시간 (0 ~ 24) : 2
주차 층 (0 ~ 9) : 5
주차 공간 (0 ~ 29) : 10
*/
검증
차량 번호 검증
// .isBlank() : 빈 값을 받지 못하도록 하는 메서드. 사용하기 직전에 null인지 아닌지 체크가 필수이다.
if(registerNumber != null && registerNumber.isBlank()) {
System.out.println("차랑번호를 반드시 입력하세요.");
return;
}
/*
차량 번호 :
차종 : 경차
입차 시간 (0 ~ 24) : 2
주차 층 (0 ~ 9) : 5
주차 공간 (0 ~ 29) : 10
차랑번호를 반드시 입력하세요.
*/
차종 검증. 경차 또는 중대형 또는 SUV가 아니면 리턴.
if(type != null && !type.equals("경차") && !type.equals("중대형") && !type.equals("SUV")) {
System.out.println("경차, 중대형, SUV 중에 하나를 입력하세요.");
return;
}
/*
차량 번호 : 가123 12
차종 : BMW
입차 시간 (0 ~ 24) : 2
주차 층 (0 ~ 9) : 5
주차 공간 (0 ~ 29) : 10
경차, 중대형, SUV 중에 하나를 입력하세요.
*/
입차시간 검증 (0 ~ 24)
if(getInTime < 0 || getInTime > 24) {
System.out.println("입차 시간은 0 ~ 24 사이어야 합니다.");
return;
}
/*
차량 번호 : 가123 12
차종 : 경차
입차 시간 (0 ~ 24) : 222
주차 층 (0 ~ 9) : 5
주차 공간 (0 ~ 29) : 10
입차 시간은 0 ~ 24 사이어야 합니다.
*/
주차 층 검증
if(parkingLayer < 0 || parkingLayer > 9) {
System.out.println("주차 층은 0 ~ 9 사이어야 합니다.");
return;
}
/*
출력 결과)
차량 번호 : 가123 12
차종 : 경차
입차 시간 (0 ~ 24) : 2
주차 층 (0 ~ 9) : 50
주차 공간 (0 ~ 29) : 10
주차 층은 0 ~ 9 사이어야 합니다.
*/
주차 공간 검증
if(parkingSpace < 0 || parkingSpace > 29) {
System.out.println("주차 공간은 0 ~ 29 사이어야 합니다.");
return;
}
/*
출력 결과)
차량 번호 : 가123 12
차종 : 경차
입차 시간 (0 ~ 24) : 2
주차 층 (0 ~ 9) : 5
주차 공간 (0 ~ 29) : 100
주차 공간은 0 ~ 29 사이어야 합니다.
*/
해당 주차 공간이 비었는지 검증
if(parkingSpaces[parkingLayer]/*층*/[parkingSpace]/*공간*/) { // -> true일 때
System.out.println("이미 주차된 공간입니다.");
return;
}
주차
parkingSpaces[parkingLayer][parkingSpace] = true;
registerNumberes[parkingLayer][parkingSpace] = registerNumber;
getInTimes[parkingLayer][parkingSpace] = getInTime;
types[parkingLayer][parkingSpace] = type;
주차 위치 확인
scanner = new Scanner(System.in);
System.out.print("확인할 차량 번호 : ");
registerNumber = scanner.nextLine();
if(registerNumber != null && registerNumber.isBlank()) {
System.out.println("차랑번호를 반드시 입력하세요.");
return;
}
/*
출력 결과)
차량 번호 : 가123 12
차종 : 경차
입차 시간 (0 ~ 24) : 2
주차 층 (0 ~ 9) : 5
주차 공간 (0 ~ 29) : 10
확인할 차량 번호 :
차랑번호를 반드시 입력하세요.
*/
boolean found = false;
// 2차 배열에는 무조건 2중 for문을 사용해야함.
for(int layer = 0; layer < registerNumberes.length; layer++) {
// 인덱스 값이 필요해서 일반 for문을 사용함
for(int space = 0; space < registerNumberes[layer].length; space++) {
// registerNumberes[layer][space] 문자열의 타입. 참조. null오류가 뜨게 된다.
// registerNumberes와 registerNumber의 위치를 바꿔도 된다.
// if(registerNumberes[layer][space].equals(registerNumber)) {
// System.out.println(layer + "층 " + space + "번에 위치합니다.");
// }
// 위에서 넘어왔기 때문에 null이 아님. null이 온다고 해도 오류가 생기지 않는다.
if(registerNumber.equals(registerNumberes[layer][space])) {
System.out.println(layer + "층 " + space + "번에 위치합니다.");
found = true; // 루프를 돌며 if문 조건에 맞는 값을 찾게 된다면 found 값이 true로 바뀐다.
break; // 원하는 값을 찾게 되어 루프를 끝낸다.
}
}
if (found) break;
}
if(!found) {
System.out.println("찾을 수 없는 차량 번호입니다.");
return;
}
/*
출력 결과)
차량 번호 : 가123 12
차종 : 경차
입차 시간 (0 ~ 24) : 2
주차 층 (0 ~ 9) : 5
주차 공간 (0 ~ 29) : 10
확인할 차량 번호 : 가123 12
5층 10번에 위치합니다.
*/
/*
출력 결과2)
차량 번호 : 가123 12
차종 : 경차
입차 시간 (0 ~ 24) : 2
주차 층 (0 ~ 9) : 5
주차 공간 (0 ~ 29) : 10
확인할 차량 번호 : 123456
찾을 수 없는 차량 번호입니다.
*/
출차 (차량번호 or 공간) 정산할 금액, 차량번호, 출차 시간.
scanner = new Scanner(System.in);
System.err.print("출차할 차량번호 : ");
registerNumber = scanner.nextLine();
System.out.println("출차 시간 : ");
int leaveTime = scanner.nextInt();
if(registerNumber != null && registerNumber.isBlank()) { // 검증
System.out.println("차랑번호를 반드시 입력하세요.");
return;
}
if(leaveTime < 0 || leaveTime > 24) {
System.out.println("출차 시간은 0 ~ 24 사이어야 합니다.");
return;
}
found = false;
int foundLayer = -1; // 차량이 위치한 층. // 00값이 나왔을 때 찾아서 00이 나온건지, 못찾아서 00이 나온건지 알 수 없기 때문에 애초에 넣을 수 없는 번호로 초기화 한다.
int foundSpace = -1; // 차량이 자리한 공간.
for(int layer = 0; layer < registerNumberes.length; layer++) {
for(int space = 0; space < registerNumberes[layer].length; space++) {
if(registerNumber.equals(registerNumberes[layer][space])) {
foundLayer = layer;
foundSpace = space;
found = true;
break;
}
}
if(found) break;
}
if(!found) {
System.out.println("찾을 수 없는 차량 번호입니다.");
return;
}
if(leaveTime < getInTimes[foundLayer][foundSpace]) {
System.out.println("출차 시간이 입차 시간보다 작을 수 없습니다.");
return;
}
/*
출력 결과)
차량 번호 : 가123 12
차종 : 경차
입차 시간 (0 ~ 24) : 2
주차 층 (0 ~ 9) : 5
주차 공간 (0 ~ 29) : 10
확인할 차량 번호 : 가123 12
5층 10번에 위치합니다.
출차할 차량번호 : 가123 12
출차 시간 :
22
출력 결과2)
차량 번호 : 가123 12
차종 : 경차
입차 시간 (0 ~ 24) : 2
주차 층 (0 ~ 9) : 5
주차 공간 (0 ~ 29) : 10
확인할 차량 번호 : 가123 12
5층 10번에 위치합니다.
출차할 차량번호 : 123456
출차 시간 :
22
찾을 수 없는 차량 번호입니다.
출력 결과 3)
차량 번호 : 가123 12
차종 : 경차
입차 시간 (0 ~ 24) : 2
주차 층 (0 ~ 9) : 5
주차 공간 (0 ~ 29) : 10
확인할 차량 번호 : 가123 12
5층 10번에 위치합니다.
출차할 차량번호 : 가123 12
출차 시간 :
1
출차 시간이 입차 시간보다 작을 수 없습니다.
*/
최종금액 (출차시간 - 입차시간) * 차량별 금액
int typeAmount =
// 삼항 연산자 조건에 따라 결과 값을 다르게 만들어진다.
types[foundLayer][foundSpace].equals("경차") ? 1000 :
types[foundLayer][foundSpace].equals("중대형") ? 1500 : 2000;
int result = (leaveTime - getInTimes[foundLayer][foundSpace]) * typeAmount;
System.out.println("최종 금액은 " + result + "원 입니다.");
// 출차 후 남은 자리
parkingSpaces[foundLayer][foundSpace] = false;
registerNumberes[foundLayer][foundSpace] = null;
getInTimes[foundLayer][foundSpace] = 0;
types[foundLayer][foundSpace] = null;
}
}
/*
출력 결과)
차량 번호 : 가123 12
차종 : 경차
입차 시간 (0 ~ 24) : 2
주차 층 (0 ~ 9) : 5
주차 공간 (0 ~ 29) : 10
확인할 차량 번호 : 가123 12
5층 10번에 위치합니다.
출차할 차량번호 : 가123 12
출차 시간 :
22
최종 금액은 20000원 입니다.
*/
객체 지향 프로그래밍 (Object Oriented Programming, OOP)
SOLID 원칙
- Single Responsibility Principle (SRP) - 단일 책임 원칙 (클래스)
- Open/Close Principle (OCP) - 개방/폐쇄 원칙
Liskov Substitution Principle (LSP) - 리스코프 치환 원칙
Interface Segregation Principle (ISP) - 인터페이스 분리 원칙 (인터페이스)
Dependency Inversion Principle (DIP) - 의존성 역전 원칙