인프런워밍업스터디_BE_5일차_과제_및_수업내용정리

오현석·2024년 2월 22일

수업 내용 정리


이런 컨트롤러 코드를 역할 분리를 통해 리팩토링하려 한다.
1. API의 진입 지점으로써의 역할은 Controller에 남겨둔다.
2. 예외 처리 및 추가적인 로직 구현은 Service 함수로 보낸다.
3. SQL을 사용하여 DB와의 통신을 담당하는 부분은 Repository로 보낸다.

USerController

@RestController
public class UserController {
    private final UserService userService;

    public UserController(JdbcTemplate jdbcTemplate){
        this.userService = new UserService(jdbcTemplate);
    }

    @PostMapping("/user")   //POST /user
    public void saveUser(@RequestBody UserCreateRequest request){
        userService.saveUser(request.getName(), request.getAge());
    }

    @GetMapping("/user")
    public List<UserResponse> getUsers(){
       return userService.getUser();
    }

    @PutMapping("/user")
    public void updateUser(@RequestBody UserUpdateRequest request){
        userService.updateUser(request);
    }

    @DeleteMapping("/user")
    public void deleteUser(@RequestParam String name){
        userService.deleteUser(name);
    }
}

UserService

public class UserService {
    private final UserRepository userRepository;

    public UserService(JdbcTemplate jdbcTemplate) {
        this.userRepository = new UserRepository(jdbcTemplate);
    }

    public void saveUser(String name, int age){
        userRepository.saveUserToDB(name, age);
    }

    public List<UserResponse> getUser(){
        return userRepository.getUserFromDB();
    }

    public void updateUser(UserUpdateRequest request){
        if(userRepository.checkUserExist(request.getId())){
            throw new IllegalArgumentException();
        }
        userRepository.updateUserToDB(request);
    }

    public void deleteUser(String name){
        String readSql = "DELETE * FROM user WHERE name = ?";

        if(userRepository.isUserNotExist(name)){
            throw new IllegalArgumentException();
        }
        userRepository.deleteUserToDB(name);
    }
}

UserRepository

public class UserRepository {
    private final JdbcTemplate jdbcTemplate;

    public UserRepository(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public void saveUserToDB(String name, int age){
        String sql = "INSERT INTO user (name, age) VALUES(?, ?)";
        jdbcTemplate.update(sql,name, age);
    }
    public List<UserResponse> getUserFromDB(){
        String sql = "select * from user";
        return jdbcTemplate.query(sql, (rs, rowNum) -> {
            long id = rs.getLong("id");
            String name = rs.getString("name");
            int age = rs.getInt("age");
            return new UserResponse(id, name, age);
        });
    }

    public boolean checkUserExist(long id){
        String readSql = "SELECT * FROM user WHERE id = ?";
        return jdbcTemplate.query(readSql, (rs, rowNum)-> 0, id).isEmpty();
    }

    public void updateUserToDB(UserUpdateRequest request){
        String sql = "UPDATE user SET name = ? WHERE id = ?";
        jdbcTemplate.update(sql, request.getName(), request.getId());
    }

    public boolean isUserNotExist(String name){
        String readSql = "DELETE * FROM user WHERE name = ?";
        return jdbcTemplate.query(readSql, (rs, rowNum)-> 0, name).isEmpty();
    }

    public void deleteUserToDB(String name){
        String sql = "DELETE FROM user WHERE name = ?";
        jdbcTemplate.update(sql, name);

    }
}

관심사의 분리를 통해 코드 리팩토링을 진행했고, jdbcTemplate를 계속해서 전달하지 않고 생성자에 jdbcTemplate을 가진 채로 혹은 객체를 생성할 때 전달해주면서 함수에서의 인자를 줄였다.

과제

클린 코드에 대한 정리

https://dev-coco.tistory.com/182

최대한 책임을 분리시키고 메소드와 변수명을 이해하기 쉽도록 작성하였다. 코드 역시 이해하기 쉽게 하고 길이도 짧게 구현하였다.

DiceGame 클래스

public class DiceGame {
    public static void main(String[] args) throws Exception{
        Player player = new Player();

        Dice dice = new Dice(6, player.getNumberOfDiceRoll());

        dice.roll();
        dice.printResult();
        System.exit(0);
    }
}

Player 클래스 - 사용자 입력 받기

import java.util.Scanner;

public class Player {
    Scanner input = new Scanner(System.in);
    public int getNumberOfDiceRoll(){
        System.out.print("숫자를 입력하시오 : ");
        return input.nextInt();
    }
}

Dice 클래스 - roll과 print 메소드에서의 책임 분리

import java.util.Arrays;

public class Dice {
    public final int diceMaxNum;
    public int[] numCount;
    public int executeNum;

    public Dice(int diceMaxNum, int executeNum) {
        this.diceMaxNum = diceMaxNum;
        this.numCount = new int[diceMaxNum];
        Arrays.fill(numCount, 0);
        this.executeNum = executeNum;
    }

    public void roll(){
        for(int i = 0; i < executeNum; i++){
            this.numCount[(int)(Math.random() * 6)] += 1;
        }
    }
    public void printResult(){
        for(int i=0; i < numCount.length; i++){
            System.out.println((i+1) + "은 "+ numCount[i] +"번 나왔습니다.");
        }
    }
}

Dice.printResult도 엄연히 다른 역할이기 때문에 다른 클래스로 분리할까 고민했지만, 클래스 자체가 너무 많아지고, Dice 클래스 내부에서 다른 메소드로도 책임 분리가 가능하다고 생각하여 이렇게 구현하였다.

profile
Backend Engineer(FastAPI, Spring, ...) / Prompt & Context Engineer / DevOps

0개의 댓글