- [Java] 121. JDBC를 활용한 CRUD와 SOLID 원칙 (2)2024년 06월 14일
- Song hyun
- 작성자
- 2024.06.14.:20
728x90반응형[Java] 121. JDBC를 활용한 CRUD와 SOLID 원칙 (2)
콘솔을 활용한 퀴즈 게임 만들기 - 리팩토링하기
*https://whatsthatsound.tistory.com/337 에서 작성한 코드를 리팩토링해보자.
* 리팩토링= 코드를 보기 좋게 정리하는 것 or 성능을 향상시키는 것.
** DB 연결을 처리하는 클래스를 따로 분리하면, 재사용성과 유지보수성이 높아진다(1) 리팩토링 1단계 : 클래스를 분리한다. (=DBConnectionManager)
*static {} 블록 - 정적 초기화 블록:
/클래스가 처음 로드될 때 한 번 실행된다. 정적 변수의 초기화나 복잡한 초기화 작업을 수행할 때 사용되며, static{} 블록 안에 예외를 던질 수도 있다.
- 메서드는 따로 분리
- 자주 쓰이는 객체는 클래스화
package com.tenco.quiz; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Scanner; import com.mysql.cj.x.protobuf.MysqlxPrepare.Execute; public class QuizGame { private static final String ADD_QUIZ=" insert into quiz(question,answer) values(?,?) "; private static final String VIEW_QUIZ=" select * from quiz "; private static final String RANDOM_QUIZ=" select*from quiz order by rand() limit 1 "; public static void main(String[] args) { try (Connection conn = DBConnectionManager.getConnection(); Scanner scanner = new Scanner(System.in);) { while (true) { printMenu(); // 블로킹 처리 int choice = scanner.nextInt(); // 블로킹 // 실행의 흐름 if (choice == 1) { // 퀴즈 문제 추가 // 사용자 퀴즈와 답을 입력받아야 함 // connection을 활용해서 query를 날려야 한다. addQuizQuestion(conn, scanner); } else if (choice == 2) { // 퀴즈 문제 조회 viewQuizQuestion(conn); } else if (choice == 3) { // 퀴즈 게임 시작 playQuizQuestion(conn,scanner); } else if (choice == 4) { // 게임 종료 System.out.println("게임을 종료합니다."); return; } else { System.out.println("잘못된 값입니다. 다시 입력해 주세요."); } } } catch (Exception e) { e.printStackTrace(); } } // end of main private static void printMenu() { System.out.println(); System.out.println("-------------------------------"); System.out.println("1. 퀴즈 문제 추가"); System.out.println("2. 퀴즈 문제 조회"); System.out.println("3. 퀴즈 게임 시작"); System.out.println("4. 종료"); System.out.println("옵션을 선택하세요."); } private static void addQuizQuestion(Connection conn, Scanner scanner) { System.out.println("퀴즈 문제를 입력하세요: "); scanner.nextLine(); String question = scanner.nextLine(); System.out.println("퀴즈 정답을 입력하세요: "); String answer = scanner.nextLine(); try (PreparedStatement pstmt = conn.prepareStatement(ADD_QUIZ)) { pstmt.setString(1,question); pstmt.setString(2, answer); int rowsInsertedCount=pstmt.executeUpdate(); System.out.println("추가한 행의 수 : "+rowsInsertedCount); } catch (SQLException e) { e.printStackTrace(); } } private static void viewQuizQuestion(Connection conn) { try (PreparedStatement pstmt= conn.prepareStatement(VIEW_QUIZ);){ ResultSet resultSet = pstmt.executeQuery(); // ResultSet을 반환한다. while(resultSet.next()) { // next:다음 값 반환 System.out.println("문제 ID : "+resultSet.getInt("id")); System.out.println("문제 : "+resultSet.getString("question")); System.out.println("정답 : "+resultSet.getString("answer")); if(!resultSet.isLast()) { System.out.println(); } } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private static void playQuizQuestion(Connection conn, Scanner scanner) { try (PreparedStatement pstmt=conn.prepareStatement(RANDOM_QUIZ)){ ResultSet rs = pstmt.executeQuery(); if(rs.next()) { String question=rs.getString("question"); String answer=rs.getString("answer"); System.out.println("퀴즈 문제 : "+question); //버그 처리 scanner.nextLine(); System.out.print("당신의 답: "); String userAnswer=scanner.nextLine(); if(userAnswer.equalsIgnoreCase(answer)) { System.out.println("정답입니다! 점수를 얻었습니다."); } else { System.out.println("오답입니다."); System.out.println("퀴즈 정답 : "+answer); } } else { System.out.println("죄송합니다. 아직 퀴즈 문제를 만들고 있습니다."); } } catch (SQLException e) { e.printStackTrace(); } } }
package com.tenco.quiz; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBConnectionManager { private static final String URL = "jdbc:mysql://localhost:3306/quizdb?serverTimezon=Asia/Seoul"; private static final String USER = "root"; private static final String PASSWORD = "asd123"; // static {} 블록 - 정적 초기화 블록 // 클래스가 처음 로드될 때 한 번 실행된다. // 정적 변수의 초기화나 복잡한 초기화 작업을 수행할 때 사용 // static{} 블록 안에 예외를 던질 수도 있다. static { try { Class.forName("com.mysql.cj.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } // 정적 메서드(함수) 커넥션 객체를 리턴하는 함수를 만들어보자. public static Connection getConnection () throws SQLException { return DriverManager.getConnection(URL,USER,PASSWORD); } }
(2) 리팩토링 2단계 : SOLID 원칙에 따라 리팩토링 해보기
*SOLID 원칙이란?- 단일 책임 원칙 (Single Responsibility Principle/SRP): 클래스는 하나의 책임만 가져야 한다.
- 개방-폐쇄 원칙 (Opne-Closed Principle/OCP): 소프트웨어 개체는 확장에는 열려 있어야 하지만, 수정에는 닫혀 있어야 한다.
- 리스코프 치환 원칙 (Liskov Substitution Principle/LSP): 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서, 하위 타입의 인스턴스로 바꿀 수 있어야 한다.
- 인터페이스 분리 원칙 (Interface Segregation Principle/ISP): 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.
- 의존성 역전 원칙 (Dependency Inversion Principle/DIP): 고수준 모듈은 저수준 모듈에 의존해서는 안 되며, 둘 다 추상화에 의존해야 한다.
1. 추상화하기 (인터페이스)
(1) QuizRepository (인터페이스)package com.tenco.quiz.ver2; import java.sql.Connection; import java.sql.SQLException; import java.util.List; import java.util.Scanner; public interface QuizRepository { int addQuizQuestion(String question, String answer) throws SQLException; // todo 수정 예정 List<QuizDTO> viewQuizQuestion()throws SQLException; QuizDTO playQuizQuestion()throws SQLException; }
(2) QuizDTO (구현클래스)package com.tenco.quiz.ver2; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; @Getter @Setter @NoArgsConstructor @AllArgsConstructor @ToString public class QuizDTO { private int id; private String question; private String answer; }
(3) QuizRepository (인터페이스 상속 클래스)package com.tenco.quiz.ver2; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import com.tenco.quiz.ver1.DBConnectionManager; public class QuizRepositoryImpl implements QuizRepository{ public static final String ADD_QUIZ=" insert into quiz(question,answer) values(?,?) "; public static final String VIEW_QUIZ=" select * from quiz "; public static final String RANDOM_QUIZ=" select*from quiz order by rand() limit 1 "; @Override public int addQuizQuestion(String question, String answer) throws SQLException{ int resultRowCount=0; try(Connection conn=DBConnectionManager.getConnection()) { PreparedStatement pstmt=conn.prepareStatement(ADD_QUIZ); //트랜잭션 처리 가능 pstmt.setString(1, question); pstmt.setString(2, answer); pstmt.executeUpdate(); } return resultRowCount; } @Override public List<QuizDTO> viewQuizQuestion() throws SQLException{ List<QuizDTO> list=new ArrayList<>(); try(Connection conn= DBConnectionManager.getConnection()) { PreparedStatement pstmt=conn.prepareStatement(VIEW_QUIZ); ResultSet rs = pstmt.executeQuery(); while(rs.next()) { int id=rs.getInt("id"); String question=rs.getString("question"); String answer=rs.getString("answer"); list.add(new QuizDTO(id,question,answer)); } } catch (Exception e) { // TODO: handle exception } return list; } @Override public QuizDTO playQuizQuestion() throws SQLException{ QuizDTO quizDTO=null; try (Connection conn = DBConnectionManager.getConnection()){ PreparedStatement pstmt=conn.prepareStatement(RANDOM_QUIZ); ResultSet rs = pstmt.executeQuery(); if(rs.next()) { int id=rs.getInt("id"); String question=rs.getString("question"); String answer=rs.getString("answer"); quizDTO=new QuizDTO(id,question,answer); } } catch (Exception e) { } return quizDTO; } }
(4) MainTest (시범 클래스)package com.tenco.quiz.ver2; import java.sql.SQLException; import java.util.List; public class MainTest1 { public static void main(String[] args) { QuizRepositoryImpl quizRepositoryImpl=new QuizRepositoryImpl(); try { // List<QuizDTO> quizDtos = quizRepositoryImpl.viewQuizQuestion(); // for(QuizDTO quizDTO : quizDtos) { // System.out.println(quizDTO); // } QuizDTO dto=quizRepositoryImpl.playQuizQuestion(); System.out.println(dto); System.out.println("정답을 맞춰주세요"); System.out.println(dto.getQuestion()); String userInput="한국"; if(dto.getAnswer().equalsIgnoreCase(userInput)) { System.out.println("정답입니다"); } else { System.out.println("오답"); } } catch (SQLException e) { e.printStackTrace(); } } }
728x90반응형'Java > 네트워크 통신' 카테고리의 다른 글
[Java] 123. HikariCP 라이브러리를 프로젝트에 추가하기 (0) 2024.06.17 [Java] 122. JDBC 성능 최적화 (0) 2024.06.17 [Java] 120. JDBC를 활용한 CRUD와 SOLID 원칙 (1) (0) 2024.06.14 [Java] 119. 트랜잭션과 배치 처리 (0) 2024.06.13 [Java] 118. 코드 예제 : 트랜잭션을 이용해 MySQL 쿼리 내부에 데이터 생성하기 (0) 2024.06.12 다음글이전글이전 글이 없습니다.댓글
스킨 업데이트 안내
현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)