병원 입원 시 관리 서비스 프로그램 기획
프로그램을 처음실행할 때는 입실 or 퇴실 서비스를 선택할 수 있다.
(입실 서비스를 선택하면,)
- 입원실의 빈자리가 있는지 확인한다.
- 입원실의 빈자리가 있으면,
- 입실서비스를 구현한다.
- 환자의 정보인 체온, 혈압(상|하)를 입력받는다. - 입력예외처리는 형식적 Validation만 진행했음 ㅎㅎ
- 받아진 환자의 정보를 토대로 입원실에 환자를 등록한다.
- 새로 업데이트된 입원실의 정보를 출력한다.
- 입원실의 빈자리가 없으면,
- 입원실 빈자리가 없음의 예외처리를 한다.
- 입원실 빈자리가 없음의 예외처리를 한다.
(퇴실 서비스를 선택하면,)
- 환자 번호를 입력받는다.
- 환자 번호에 따른 입원실에 환자가 존재하는지 확인한다.
- 입원실에 환자가 존재한다면,
- 환자를 퇴실시킨다.
- 새로 업데이트된 입원실의 정보를 출력한다.
- 입원실에 환자가 존재하지 않는다면,
- 환자가 존재하지 않는다는 예외처리를 한다.
다음과 같이 병원 입원실 관리 서비스 프로그램을 구현된다.
그리고, 서비스는 무한반복으로 구동되도록 구현하면 된다 ㅎㅎ!
프로그램 설계 - MVC 아키텍처 설계
도교수님이 설계한 MVC 아키텍처이다.
아래와 같이 교수님은 설계하셨고, 나름 도교수님만의 설계방식인 듯하다.
코드 구현
Model 클래스
HospitalMainModel 클래스
해당 Model 클래스는 병원 입원실 관리와 관련한 기능을 구현했다.
입원실의 빈방이 존재하는지 확인을 한다.
입원실에 새로운 환자를 등록한다.
입원실에 환자를 퇴실시킨다.
// 다하고 Main Model 2차원 배열로 풀어보기 ㅎㅎ
// 2차원 배열과 다른 개념... ㅎㅎ
// 객체 타입으로 배열 객체를 생성한다.
public class HospitalMainModel {
private HospitalPatientModel[] rooms; // 입원실 배열
private int occupied; // 환자가 입실중인 입원실의 개수
// 생성 메서드
public HospitalMainModel(int n) { // 병원 객체 생성 초기화 메소드, n = 병원이 보유한 입원실의 개수
rooms = new HospitalPatientModel[n];
occupied = 0;
// 디버깅 코드
// PatientModel 타입의 배열 객체 rooms는 null 값을 갖는다.
System.out.println(rooms[0] == null);
System.out.println(rooms.length);
/*
* 2차원 배열이 아닌, 타입이 객체인 배열 객체이다.
* 그래서, 배열 원소 하나가 선언한 타입 객체 형태로 저장된다.
* [ {HostpitalPatient}, {HospitalPatientModel}, {HospitalPatientModel}, {HospitalPatientModel}]
* 위와 같은 형태로 rooms 배열 객체가 선언되어 있다.
* (결국, 객체 타입으로 )
*/
}
/**
* 입원실 배열을 리턴한다.
* @return
*/
// Patient Model 타입의 배열 객체를 생성한다.
public HospitalPatientModel[] getRoomsInfo() {
return rooms;
}
/** [1번 - 배점 2점]
* 비어있는 입원실이 있는지 여부를 리턴한다.
* @return
*/
public boolean roomAvailable() {
for (int i = 0; i < rooms.length; i ++) {
if(rooms[i] == null) {
return true;
}
}
return false;
}
/** [2번 - 배점 5점]
* 환자 등록번호 id로 입원 중인 환자를 찾는다.
* @param id
* @return 환자
*/
// return 타입은 HospitalPatientModel 로 생성메서드에서 할당해준 타입들이다 ㅎㅎ (rooms 배열을 return)
public HospitalPatientModel findPatient(int id) {
// 환자 id와 일치한 환자가 입원실에 존재하는지 찾기 - (객체 배열 활용 ㅎㅎ)
// 비교 연산 시 어떤 순간에 null 값이 온다면, Null 에러가 발생 - 단축계산 원리로 에러를 해결함!
for(int i = 0; i < rooms.length; i ++) {
if(rooms[i] != null && rooms[i].getID() == id) {
return rooms[i];
}
}
// null 객체는 초기화하기 전의 값이므로, 받아지는 듯
return null;
}
/** [3번 - 배점 5점]
* 환자 p를 입실시킨다.
* @param p
* @return 빈 입원실이 있어서 입실 성공하면 true, 없어서 실패하면 false
*/
public boolean admit(HospitalPatientModel p) {
if(roomAvailable()) {
for(int i = 0; i < rooms.length; i ++) {
if(rooms[i] == null) {
rooms[i] = p;
return true;
}
}
}
return false;
}
/** [4번 - 배점 5점]
* 환자 p를 퇴실시킨다.
* @param p
* @return 환자를 찾아서 퇴실 성공하면 true, 실패하면 false
*/
public boolean discharge(HospitalPatientModel p) {
if(findPatient(p.getID()) == null) {
return false;
}
else {
// 환자 p를 퇴실시키기
for(int i = 0; i < rooms.length; i ++) {
if(rooms[i] != null && rooms[i].getID() == p.getID()) {
rooms[i] = null;
return true;
}
}
}
// 해당 boolean은 값을 가지지 않음 - 형식상 데이터
return true;
}
}
HospitalPatientModel 클래스
환자 Index
환자 체온
환자 혈압(상 | 하)를 저장해둔다.
public class HospitalPatientModel {
private int patient_id; // 환자 등록번호
private double temperature; // 환자 체온
private int blood_pressure_high; // 환자 혈압 (위)
private int blood_pressure_low; // 환자 혈압 (아래)
// 환자 객체 생성 초기화 메소드
public HospitalPatientModel(int id, double t, int high, int low) {
patient_id = id;
temperature = t;
blood_pressure_high = high;
blood_pressure_low = low;
}
public int getID() {
return patient_id;
}
public double getTemp() {
return temperature;
}
public int getBPHigh() {
return blood_pressure_high;
}
public int getBPLow() {
return blood_pressure_low;
}
}
View 클래스
HospitalViewOut 클래스
병원 입운실 관리 서비스의 Java GUI를 출력한다.
import java.awt.*;
import javax.swing.*;
public class HospitalViewOut extends JPanel {
private HospitalMainModel hospital;
// 생성 메서드
public HospitalViewOut(HospitalMainModel h) {
hospital = h;
JFrame f = new JFrame();
f.getContentPane().add(this);
f.setLocation(200,200);
f.setTitle("ERICA 병원");
f.setSize(400, 400);
f.setVisible(true);
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public void paintComponent(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, 400, 400);
g.setColor(Color.black);
int y = 100;
paintHeader(g, 100, y);
HospitalPatientModel[] rooms = hospital.getRoomsInfo();
for (int i = 0; i < rooms.length; i++) {
HospitalPatientModel p = rooms[i];
if (p != null) {
y += 30;
paintRow(g, p, i, 100, y);
}
}
}
private void paintHeader(Graphics g, int x, int y) {
g.drawString("병실", x, y);
x += 50;
g.drawString("환자", x, y);
x += 50;
g.drawString("체온", x, y);
x += 50;
g.drawString("혈압", x, y);
}
private void paintRow(Graphics g, HospitalPatientModel p, int r, int x, int y) {
g.drawString(Integer.toString(r), x, y);
x += 50;
g.drawString(Integer.toString(p.getID()), x, y);
x += 50;
g.drawString(Double.toString(p.getTemp()), x, y);
x += 50;
String high = Integer.toString(p.getBPHigh());
String low = Integer.toString(p.getBPLow());
g.drawString(high+"/"+low, x, y);
}
/**
* 병원 입원실의 입실 상황을 보여준다.
*/
public void display() {
this.repaint();
}
/**
* 메시지 대화창에 전달할 메시지를 띄운다.
* @param message - 전달할 메시지
*/
public void showMessage(String message) {
JOptionPane.showMessageDialog(null, message);
}
}
HospitalViewIn 클래스
ViewIn 클래스는 서비스 선택과 관련한 문자 정보,
환자의 정보를 입력받는다.
import javax.swing.JOptionPane;
public class HospitalViewIn {
/**
* 입력 대화창을 띄워 +와 - 둘 중 하나만 받아 리턴한다.
* @param message 인풋 대화창에 보여줄 메시지
* @return "+" 또는 "-"
*/
public String readMenu(String message) {
String input = JOptionPane.showInputDialog(message);
while (! (input.equals("+") || input.equals("-")))
input = JOptionPane.showInputDialog(message);
return input;
}
/**
* 입력 대화창을 띄워 받은 입력을 정수로 변환하여 리턴한다.
* @param message 인풋 대화창에 보여줄 메시지
* @return 정수
*/
public int readInteger(String message) { // 입력 오류 처리 생략
String input = JOptionPane.showInputDialog(message);
int n = Integer.parseInt(input);
return n;
}
/**
* 입력 대화창을 띄워 받은 입력을 실수로 변환하여 리턴한다.
* @param message 인풋 대화창에 보여줄 메시지
* @return 실수
*/
public double readDouble(String message) { // 입력 오류 처리 생략
String input = JOptionPane.showInputDialog(message);
double r = Double.parseDouble(input);
return r;
}
}
Controller 클래스
HospitalController 클래스
ViewIn으로 부터 서비스 선택을 받고,
받아진 선택으로 서비스를 나눠서 구현한다.
입실 서비스면,
Model 객체로부터 입원실에 빈방이 존재하는지 확인을 한다.
입원실에 빈방이 존재한다면,
VIewIn으로 부터 환자 정보를 가져오고
가져온 정보로 Model 객체에 선언한 rooms 객체 (입원실 환자 정보)를 "입실"하여 업데이트 한다.
그리고, ViewOut으로부터 업데이트 된 입원실 환자 정보를 출력한다.
퇴실 서비스면,
ViewIn으로 부터 환자 Index를 가져오고,
가져온 정보로 환자가 존재하는지 Model 객체에서 확인한다.
환자 Index가 입원실에 존재한다면,
Model 객체에 선언한 rooms 객체 (입원실 환자 정보)를 "퇴실"하여 업데이트 한다.
그리고, ViewOut으로부터 업데이트 된 입원실 환자 정보를 출력한다.
예외되는 상황들은 예외 ViewOut으로 처리하도록 설계하였다.
병원 입원실 관리 서비스 프로그램은 무한반복 로직으로 별도의 종료처리가 되어있지 않다는 점을 유의하자 !!
import javax.swing.*;
public class HospitalController {
private HospitalMainModel hospital; // 병원 객체
private HospitalViewOut displayer; // 출력 객체
private HospitalViewIn reader; // 입력 객체
private int new_id = 1001; // 신규 환자 등록번호, 1001 = 첫 환자의 등록번호 (고유 등록 번호임 ^.^)
// 생성 메서드 - 필드변수 초기화 & {객체 선언}
public HospitalController(HospitalMainModel h, HospitalViewOut d, HospitalViewIn r) {
hospital = h;
displayer = d;
reader = r;
}
// 입원실 관리 서비스 (무한 루프)
// [5번 - 배점 10점]
public void manageRooms() {
while (true) {
double temperature;
int bp_high, bp_low, id;
HospitalPatientModel p;
String UserSelectService = reader.readMenu("+: 입실, -: 퇴실");
System.out.println(UserSelectService);
// 입실 서비스 - 자바에서 문자열 비교는 .equals() 함수를 사용한다.
if (UserSelectService.equals("+")) {
if(hospital.roomAvailable()) {
// 환자 상세 정보 기입
temperature = reader.readDouble("체온?");
bp_high = reader.readInteger("혈압(상)");
bp_low = reader.readInteger("혈압(하)");
// 첫 환자일 때의 입원 서비스
if(new_id == 1001) {
// 객체를 선언 후 활용한다.
p = new HospitalPatientModel(new_id, temperature, bp_high, bp_low);
hospital.admit(p);
displayer.display();
new_id = new_id + 1;
}
else {
p = new HospitalPatientModel(new_id, temperature, bp_high, bp_low);
hospital.admit(p);
displayer.display();
new_id = new_id + 1;
}
}
else {
displayer.showMessage("병실이 없습니다.");
}
}
// 퇴실 서비스
else {
id = reader.readInteger("환자 번호?");
// 환자 퇴실 시키기
if(hospital.findPatient(id) != null) {
p = hospital.findPatient(id);
hospital.discharge(p);
displayer.display();
}
else {
displayer.showMessage(id + " 환자를 찾을 수 없습니다.");
}
}
}
}
}
Starter 클래스
HospitalStarter 클래스
Starter 클래스에서 Controller에서 사용할 HospitalModel 클래스를 객체로 생성하고,
넘겨준다.
따라서, Starter는 전체 프로그램의 통제 역할로
프로그램 구현에 필요한 모든 클래스를 객체로 만들고 넘겨주는 역할을 담당한다.
public class HospitalStarter {
public static void main(String[] args) {
HospitalMainModel h = new HospitalMainModel(4);
new HospitalController(h, new HospitalViewOut(h), new HospitalViewIn()).manageRooms();
}
}
트러블 슈팅 - 프로그램 제작 시 어려웠던 점
객체를 타입으로 가지는 변수| 배열은 초기화하기 전에는 Null 값을 가진다.
int로 필드 변수를 선언 후 초기화하기 전에는 0 값을 자동으로 가진다.
하지만, 객체를 타입으로 가지는 변수는 초기화하기 전에는 Null 값을 자동으로 가진다.
String 타입의 변수와 비교연산을 할 때는 "==" 연산을 수행하지 못한다.
String 타입의 변수는 비교연산 시 == 대신,
.equals(); 메소드를 사용한다.
객체의 의의 - 객체는 클래스의 "틀"
Starter에서 Model 클래스, View 클래스를 객체로 생성한 뒤
Controller에 보내준다.
그리고, Controller에선, Model, View 객체를 받아서
사용하게 되고, 고유의 객체로써 객체를 사용해 전역변수를 업데이트하면,
객체가 업데이트 된다. - 이 부분에 대해선, 자세히 아는 건 아니라, 참고만 하기
(node.js와 같이 함수형 언어보다,
객체지향 프로그래밍 언어인 자바가 체계적으로 소스코드를 관리를 할 수 있다.
그리고, 함수의 return 값을 받아 전달해주는 작업이 덜 필요한 듯하다~ - 객체를 이용한 것만으로 전역변수로써 값을 변경할 수 있다.
아직까지 잘 모르겠지만, 객체의 개념을 활용해 더 깊은 작업을 유연하게 할 수 있을 것 같다.
그래도 나름 자바 처음이지만, 재미있는 것 같다 ㅎㅎ
객체를 타입으로 가지는 배열 객체
객체를 타입으로 가지는 배열 객체는 생각보다 단순하다.
원소의 하나가 객체의 타입으로 지정되어 있는 것이다
그렇기에, 원소에 접근할 때 객체임을 유의하면서 사용해야 한다 ㅎㅎ
'CS 대학강의' 카테고리의 다른 글
[CS 1-2 | 프로그램 설계 방법론] Java 인터페이스와 상속 10주차 (0) | 2022.10.27 |
---|---|
[CS 1-2 | 오픈소스 SW 기초] 가상화 & 리눅스 컨테이너 with Docker 6주차 (0) | 2022.10.20 |
[CS 1-2 | 프로그램 설계 방법론] Java로 스도쿠 프로그램 제작 (0) | 2022.10.18 |
[CS 1-2 | 프로그램 설계 방법론] 배열 객체 & MVC 아키텍처 설계 실제 프로그램에 적용해보기 9주차 (2) | 2022.10.15 |
[CS 1-2 | 오픈소스 SW 기초] 네트워크 통신 | 소켓 통신 5주차 (0) | 2022.10.13 |