KDT 공부 일지 - 2026.01.13_1

김시코·2026년 1월 13일

KDT 공부 일지

목록 보기
6/27

2026년 1월 13일 화요일 - 4주차


오늘은 저번에 작성했던 학생 관리 프로그램을 클래스를 사용해서 작성한다.

클래스를 사용한다는 것은 속도적인 면을 일부 포기 한다는것. 클래스를 사용하기 시작하는 순간보다는 가독성과 철학을 우선시 해야 한다.

패키지 이름을 작성할때는 com.소속기관.프로젝트명.상위기능이름.하위기능... 식으로 작성한다.

  • 컴포넌트: 로직을 다루는 객체 (추상화 레벨이 높음) <--> DTO
    컨트롤러 역할: 사용자의 입출력을 담당함(최전방) 큰 흐름을 제어하며, 비즈니스(코어) 로직이 필요할땐 서비스(컴포넌트)를 선택해서 활용한다. (컴포넌트의 하위 개념). 사용자에게 입력을 받아서 필요한 서비스를 선택해, 입력 받은 데이터를 전달해준다. 그 후 서비스가 연산을 실행하고 도출한 결과값을 받아서 사용자에게 결과값을 출력한다.
  • 서비스: 비즈니스 로직이 들어있음. 컨트롤러를 통해 입력을 받아 로직을 수행한 후, 결과값을 컨트롤러에게 돌려줌. 사실은 절대 사용자 입출력과는 관계가 없어야 하며, 순수한 데이터만을 가지고 알고리즘을 처리 해야 한다.
  • IoUtil: 입출력을 위한 Scanner, print 등을 만들기 위함. scanner 인스턴스를 static으로 한번만 생성해서 재활용 하기 위해서 정의하며, 이 안에 System.out.println();가 들어있는 메서드 print와, scanner.nextLine();가 들어있는 메서드가 있다. python 스타일로 IO를 관리 하기 위해서 사용한다.
  • 3-Layer Architecture(3중 레이어 구조): Controller가 Service를 생성하고 Service가 Repository를 생성한다.

또한, 지난번 학생관리 프로그램에서도 사용했던, 사용자가 결과값을 받아본 후에 Enter를 눌러야만 다음으로 넘어가게 하는 기능을 위한 메서드 pause가 있다. 즉, 로우레벨의 입출력을 한번 감싸는 것. 여기에는 다 public staic으로 만들었기 때문에 남을 위한것이며, 인스턴스가 필요가 없다. 그렇기에 생성자를 privte로 막아둬야 한다.

「"역할을 분리하였기 때문에 입출력시 System.out.println이나 scanner를 사용하지 않고 IoUtil에 작성해둔 print, input를 사용해야 한다."」

  • public 메서드: 남을 위해서 만든것. 내가 아닌 남이 사용한다.
  • IO: input, output
  • 비즈니스 로직: 실질적인 로직, 주요 핵심 로직.
  • Repository: 저장소. 데이터의 관리에만 관심을 가지는 역할. - 지금은 직접 구현하지만, 나중에는 데이터베이스가 관리 한다(SQL - CRUD). 우리가 로직을 직업 작성하지는 않음.
  • CRUD = Creat, Read, Update, Delete

[StudentManagerV2]

[App]
import com.joongang.stm.controller.StudentMAnagerController;

public class App {
    public static void main(String[] args) throws Exception {
    /*  StudentMAnagerController controller = new StudentMAnagerController();
        controller.run();   */  // 이렇게 쓰기도 하지만 보통은 아래처럼 한줄로 쓴다.
        
        new StudentMAnagerController().run();
        // 보통 main에는 이 한줄 이상으로 쓰지 않는다.
        // 이름이나 그런걸 내 마음대로 할 수 없기 때문에.
    }
}
[StudentDto]
package com.joongang.stm.dto;

// DTO (Vo, Entity)
// 필드 정의가 핵심
public class StudentDto {   
    private String name;
    private int age;
    private int score;

    // 생성자와 setter, getter 추가 (공식. 외우기)
    public StudentDto(String name, int age, int score) { // 생성자
        this.name = name;
        this.age = age;
        this.score = score;     // 이렇게 쓰면 All argument Constructer
    }

    public StudentDto() { }     // 이렇게 쓰면 No argument Constructer

    // setter, getter
    public void setName(String name) {
        this.name = name;
        // this 빼면 둘다 지역변수가 되어버려서 위에 있는 name을 가져올 수가 없음
    }
    public String getName() {
        return name;		// 문법적으로는 this.name이다. (생략된거)
        // 위에는 this가 있는데, 여기에는 없는 이유로는 this는 같은 이름을 가지는
        // 지역변수(아규먼트)가 있어서 어디에 있는 변수인지 구분을 하기 위해서 사용하는것.
       	// 근데 여기는 같은 이름을 가지는 변수가 없으니까 생략이 가능하다.
    }

    public void setAge(int age) {
        this.age = age;
    }
    public int getAge() {
        return age;
    }

    public void setScore(int score) {
        this.score = score;
    }
    public int getScore() {
        return score;
    }
}
[IoUtil]
package com.joongang.stm.util;

import java.util.Scanner;
// 약간 ptyhon 스타일로 가기 위해서. inut, output을 깔끔하게.
// 유틸 클래스: 로직을 보조용 클래스
// 이 클래스를 정의한 이유
// 1. 스태틱 공부 목적
// 2. System, Scanner라는 방대한 클래스의 사용 범위를 제한
public class IoUtil {
    private static final Scanner scanner = new Scanner(System.in);

    private IoUtil() { }
    	// 인스턴스 생성 불가. static으로만 이루어진 클래스는 생성자를 막아둬야 한다.

    public static void print(String message) {
        System.out.println(message);
    }

    public static String input(String perompt) {
        System.out.print(perompt);
        return scanner.nextLine();
    }

    public static void pause() {
        System.out.print("계속 하시려면 Enter를 입력하세요...");
        scanner.nextLine();
    }
}
[StudentManagerController]
package com.joongang.stm.controller;

import com.joongang.stm.service.StudentManagerService;
import com.joongang.stm.util.IoUtil;

public class StudentMAnagerController {

    private StudentManagerService service = new StudentManagerService();
	// ㄴ 멤버변수니까 private. 서비스가 컨트롤러에 귀속되지 않게 하기 위해서 사용.
    
    public void run() {
        // 실질적 시작 시점
        IoUtil.print("******************************");
        IoUtil.print("*     학생 관리 프로그램     *");
        IoUtil.print("******************************");

        while (true) {
            IoUtil.print("======== 메뉴 ========");
            IoUtil.print("1. 등록");
            IoUtil.print("2. 목록");
            IoUtil.print("3. 검색");
            IoUtil.print("4. 삭제");
            IoUtil.print("5. 수정");
            IoUtil.print("6. 통계");
            IoUtil.print("0. ㅍ로그램 종료");
            String command = IoUtil.input("명령 입력> ");

            if(command.equals("0")) {
                break;
            }

            if(command.equals("1")) {
                // 등록에 해당하는 핵심 로직(서비스) - 컴포넌트(인스턴스가 있어야 함)
                service.register();
            } else if(command.equals("2")) {
                service.list();
            } else if(command.equals("3")) {

            } else if(command.equals("4")) {
                
            } else if (command.equals("5")) {

            } else if (command.equals("6")) {

            } else {
                IoUtil.print("잘못된 멸령을 입력하셨습니다. 다시 입력해주세요.");
            }

            IoUtil.pause();
        }

        IoUtil.print("프로그램이 종료됩니다.");
        IoUtil.print("이용해주셔서 감사합니다.");
    }
}
[StudentManagerService]
package com.joongang.stm.service;

import com.joongang.stm.dto.StudentDto;
import com.joongang.stm.repository.StudentManagerRepository;
import com.joongang.stm.util.IoUtil;

// 컴포넌트
// 서비스: 주요 핵심 로직 = 비즈니스 로직
// 사실은 절대 사용자 입출력과는 관계가 존재 해서는 안된다.
// 이번 코드에서는 위에 범위를 넘어선다(문제)
// 순수한 데이터만 가지고 알고리즘을 처리 해야 함

public class StudentManagerService {
    
    private StudentManagerRepository repository = new StudentManagerRepository();

    public void register() {
        IoUtil.print("====== 학생 정보 등록 ======");
        String name = IoUtil.input("이름 > ");
        int age = Integer.parseInt(IoUtil.input("나이 > "));
        int score = Integer.parseInt(IoUtil.input("점수 > "));

        StudentDto studentDto = new StudentDto(name, age, score);
        // 생성자를 사용해서 초기화 하고 값을 넣음
        repository.save(studentDto);

        IoUtil.print("============================");
    }

    public void list() {
        IoUtil.print("====== 학생 정보 목록 ======");

        StudentDto[] studentList = repository.findAll();
        int count = repository.count();

        for(int i = 0; i < count; i++) {
            String text = "";
            text += "이름: " + studentList[i].getName();
            text += ", 나이: " + studentList[i].getAge();
            text += ", 점수: " + studentList[i].getScore();
            IoUtil.print(text);
        }

        IoUtil.print("총 " + count + "명이 존재 합니다.");

        IoUtil.print("============================");
    }

    public void serch() {
        IoUtil.print("====== 학생 정보 검색 ======");

        IoUtil.print("============================");
    }
}
[StudentManagerRepository]
package com.joongang.stm.repository;

import com.joongang.stm.dto.StudentDto;

// Repository = 저장소. 데이터의 압출력 관리에만 관심을 가지는 역할 나중에는 DB로 함
public class StudentManagerRepository {
    private StudentDto[] studentList = new StudentDto[5];
    // ㄴ studentList 변수에 StudentDto의 필드값을
    private int count = 0;

    public void save(StudentDto studentDto) {
        studentList[count] = studentDto;
        count++;
    }

    public StudentDto[] findAll() {
        return studentList;
    }

    public int count() {
        return count;
    }
}

[StudentManagerV2 클래스 다이어그램]

『앞으로의 수업은 "지금까지의 수업"에 비하면 전혀 중요하지 않다.
물론 중요하긴 하지만. 오늘 한것을 모르면 의미가 없기 떄문에.
지금까지가 부족하다고 판단되면, 수업은 듣되 이 코드를 이해하고, 반복해라.』

[이해해야 할것]

  • 이 코드를 기준으로 "문법" 공부
  • 전체적으로 코드 흐름 이해(메서드)
  • 클래스의 구조에 대한 아해(왜 이런 클래스를 정의해했는가?)
    반복 << 필수 (몸으로 익혀라)

클래스 다이어그램을 보고 복기가 가능하면 하고싶은 공부해라.

필수는 아니지만, 새로운 프로그램을 만들어보기 -> 할일관리, 가계부... 스스로 기획

profile
취업하고싶다...

0개의 댓글