주노 님의 블로그

20240726 본캠프 10일차 TIL 본문

TIL

20240726 본캠프 10일차 TIL

juno0432 2024. 7. 26. 22:24

 

본캠프 10일차 내용 간단요약

  • 09:00 ~ 10:30 : 코드카타
  • 11:00 ~ 12:00 : 튜터님 면담 & 팀원 대화 
  • 12:00 ~ 13:00 : 점심시간
  • 13:00 ~ 14:00 : 개인 과제 TIL 정리
    LV3 Enum 공부 및 구현
  • 14:00 ~ 18:00 : 복습
  • 15:00 ~ 15:30 : 1ON1면담
  • 18:00 ~ 19:00 : 저녁시간
  • 19:00 ~ 20:00
  • 20:00 ~ 02:00 : 고찰
    현재 과제가 개방 폐쇄의 원칙을 지킬 수 있을지.!
    현재 과제가 getter과 setter의 의미가 있는지
    현재 과제가 단일 클래스 원칙을 지킬 수 있을지

오늘 해야할 일✔️ 🔺 ❌

✔️ 개인과제2

❌ 개인과제 3-1
❌ 개인과제 예외처리

✔️ 3주차 4주차 복습


코드카타 - SQL

더보기

REST_INFO와 REST_REVIEW 테이블에서 서울에 위치한 식당들의 식당 ID, 식당 이름, 음식 종류, 즐겨찾기수, 주소, 리뷰 평균 점수를 조회하는 SQL문을 작성해주세요. 이때 리뷰 평균점수는 소수점 세 번째 자리에서 반올림 해주시고 결과는 평균점수를 기준으로 내림차순 정렬해주시고, 평균점수가 같다면 즐겨찾기수를 기준으로 내림차순 정렬해주세요.

 

라는 문제가 있다

 

SELECT ri.rest_id, ri.rest_name, ri.food_type, ri.favorites, ri.address, round(avg(rr.review_score),2) score
from rest_info ri inner join rest_review rr on ri.rest_id = rr.rest_id
where ri.address like "서울%"
group by ri.rest_id
order by score desc, ri.favorites desc

 

 

왜지 왜지 왜지 왜지 싶었는데

%서울% 라고 적어놧었다...

 설마설마설마 했는데...

정답이더라..

 

뭔가 ADDR에 서울이랑 서울특별시 이렇게 되어있길래 혹시 모르니 대한민국 서울시 이런게 있지않을까 싶었는데 아뉘더라 ㅇㅇ.. 문제탓임..

일단 LEFT나 RIGHT조인을 쓰지않은게 아예 NULL인경우가 많아서 NULL을 정렬할수는 없으니까 INNERJOIN으로 사용했다

 


1ON1면담

더보기

1on1면담
튜터님께서 말씀해주신 내용이 엄청나게 도움이 되는 시간이었다
쉽게 요약하면

TIL을 작성하는데 시간이 오래 걸린다
이미 물어본거고 답을 찾았는데 튜터님께 또 물어보니 칭찬을 받았다
세상마상 너무 두서없이써서 칭찬 받을줄은 몰랐는데 당황쓰
TIL은 엄청 풀어서 쓰고, 따로 카테고리로 예쁘게 정리해야겠다

오류와 궁금한점을 챗지피티에게 물어볼까 구글링을 해볼까
기초 지식은 챗지피티한테 물어볼 수 있지만, 연차가 쌓이고 난이도가 올라가게된다면, 챗지피티의 신뢰도는 떨어진다
지금 쉬운 개념을 구글링하는 법을 배워서 검색하는 실력을 가지라 하셨는데 놀랍게도 오늘 써먹을 줄은 몰랐다

TIL을 적을때 이게 잘못된 내용인지 잘된 내용인지 구분이 안될때가 많다
기술 블로그는 대부분 대학생이나, 취준생들이 많이 작성을한다. 그 글이 잘못된 내용도 많다
틀려도 그닥 문제가 되진 않을것 같다

추천하시는 서적이나 강의가 있을까요
스프링 강의 들어둬라. 스프링을 처음 배우는거라면 출발선상이 비전공자랑 똑같을 것이다. 그다음주에 나올 내용을 키워드를 파악하고
미리 공부해두면 남들보다 이해도 더 잘 갈것이고, 능력이 훨씬 오를것이다, 만약 강의를 빨리 학습해서 남은 시간에 본인이 원하는 분야를 파고들면
최종 프로젝트전에 하는 프로젝트에서 더 배운걸 써먹고, 오류가 많이 발생할것이다, 그걸 관리해서 최종프로젝트때 써먹으면 좋을것같다


개인과제 - LV2

더보기

1 Calculator 클래스 구현

public class Calculator {
    List<Integer> results = new ArrayList<>();

    public int calculate(int num1 , int num2, char operater) throws Exception
    { ...
                        throw new ArithmeticException("두번째 입력값은 0이 될 수 없습니다.");
                }
                else
                {
                    result = num1 / num2;
                }
                break;
            default:
                throw new ArithmeticException("연산자 에러입니다");
        }

익셉션을 던지라해서 만들어봣는데

생각해보니 연산자에러는 ILLIGAL ~... 이 나을거같다. ARITHMETIC은 연산 중 내용에 가깝기때문에 ILLIGAL로 바꿔야겠다!

 

2 Calculator 클래스 사용

 //과제 2-2 Calculator 객체 생성
        Calculator calculator = new Calculator();
        
                    try {
                result = calculator.calculate(num1, num2, operator);
                System.out.println("결과 : " + result);
            }catch (Exception e)

익셉션을 THROWS 받았기때문에 사용하는곳에서는 TRY CATCH문 등으로 예외를 처리해줘야한다.

 

3 캡슐화

 //과제 2-3 접근제어자 private를 통해 캡슐화를 한다.
    private List<Integer> results = new ArrayList<>();
    
    ...
    
     //getter와 setter로
    public List<Integer> getResults() {
        return results;
    }

    public void setResults(int result) {
        results.add(result);
    }

필드는 다른곳에서 쓰지못하게 캡슐화를 하는게 좋다

getter와 setter를 만들어서 간접적으로 접근을 하도록 한다.

getter와 setter는 어디다 써야할까 고민을 하였다

이미 조회 메서드도 따로 있었고 setter는 list를 수정하기에는 무리가있지않을까 생각을 하여서

쓰지않은채로 놔두긴 했는데

 

오늘 아침 튜터님께서 하신 말씀이

지금은 배운걸 써먹는 과제기때문에 모든 내용을 써보는 취지로 하라고 하시더라

 

setter를 지양하라고 옛날 수업시간 중 기억의 편린에서 듣긴했는데

이것도 공부해봐야겠다..

 

4 삭제 메서드 구현

//과제2-4 removeResult 메서드 생성
    public void removeResult() {
        results.remove(0);
    }
    
    ///////
    
    //과제 2-4 removeResult메서드 사용
            System.out.println("가장 먼저 저장된 연산 결과를 삭제하시겠습니까? (remove 입력 시 삭제)");
            if (sc.next().equals("remove")) calculator.removeResult();

쉬운거니까 냉무

 

5 조회 메서드 구현

//과제 2-5 inquiryResult 메서드 사용
            System.out.println("저장된 연산결과를 조회하시겠습니까? (inquiry 입력 시 조회)");
            if (sc.next().equals("inquiry"))
            {
                calculator.inquiryResults();
            }
            
            /과제 2-5 연산 결과 리스트 조회메서드.
    public void inquiryResults() {
        System.out.println(Arrays.toString(getResults().toArray()));
    }

이거는 만들기 전부터 삭제나 삽입이 잘 되고 있는지 확인하는 용도로 놔뒀었는데 좋은것 같다

 

6 생성자를 통해 초기화하기

//과제 2-6 초기화 생성자
    public Calculator(){
        this.results = new ArrayList<>();
    }

 

 생성자가 없으면 디폴트 생성자로 만들어지게 된다.

하지만 하나의 생성자라도 있으면 디폴트생성자는 없어지고 그 생성자만이 남게된다.

뭐가 다른가? 생각할수도 있지만

디폴트생성자는 그냥 껍데기만 생성하는것이고 만약 사전에 조회 , 수정, 삭제등의 작업을 처리한다면 null값을 가지고있는 객체는 예외가 발생해버린다

초기화를 하게되면 예상가능한 선이 된다는 뜻?

 

main문은 바꿀게 없어보인다

 

7 원의 넓이 구하는 메서드

       System.out.print("반지름을 입력하세요");
                    double r = sc.nextDouble();
                    calculator.calculateCircleArea(r);
                    calculator.inquiryResultsCircleArea();
                    
                     public double calculateCircleArea(double r) {
        double result = r*r*PI;
        setResultsCircleArea(result);
        return result;
    }

    public List<Double> getResultsCircleArea() {
        return resultsCircleArea;
    }

    public void setResultsCircleArea(double r) {
       resultsCircleArea.add(r);
    }

    public void inquiryResultsCircleArea() {
        System.out.println(Arrays.toString(getResultsCircleArea().toArray()));
    }

 

말 그대로 조회하기위해 원의 넓이를 구하는 메서드들도 추가로 작성해주었다

 

private final Double PI = 3.14;

 밤중에 짠 코드의 문제점

항상 밤중에 코드를짜면 대입 안해놓고 0이나와서 계속 찾아다니거나

for(int~~); 이렇게 해놓고 반복문이 왜 안돌지... 하고있다

 

PI같은건 절대로 불변하는 값이다 프로그램이 종료되어도, 우리가 죽어도!

그래서 private static final double PI = 3.14; 로 지정해줘도 괜찮은데

스태틱도 없고... 래퍼형 double로 선언되었다

 

8 기능 분리

SOLID라는 단어가 있다

객체지향의 5가지 원칙인데

그중에서 단일 책임의 원칙이다

 

지금 CALCURATOR은 기능이 엄청나게 많이 되어있다

원 계산, 사칙연산 계산등

일단은 원과 사칙연산만 분리해보자..

 

ARITHMETICCALCULATOR을 만들고

CIRCLECALCULATOR 클래스를 만들어서 기능 분리를 해준다

 

protected List<Double> results = new ArrayList<>();

public class Calculator {
    protected List<Double> results = new ArrayList<>();

    public void addResult(double result) {
        results.add(result);
    }

    public void removeResult() {
        results.remove(0);
    }

    public void inquiryResults() {
        System.out.println(results);
    }
}

 확 줄어든것을 볼 수 있다

여기서 더 분리해야하는게 맞긴한데 요구사항에 arithmetic과 circle만 분리하래서 이렇게 구현
진짜 단일책임으로 하려면 저장 삭제 조회도 분리하면 좋을거같다고 생각했다

 

9 arithmetic 기능 또 분리

현재 ariithmetic은 덧셈 뺄셈 나눗셈 곱셈을 모두 수행하고있다.

진짜 단일 책임의 원칙이라면 여기서는 계산 만 수행하는게 좋을것이다. 

그래서 

이렇게 구현이 된것을 볼 수 있다

package calculator;

//2-8 단일 책임의 원칙 구현
public class ArithmeticCalculator extends Calculator {
    //2-9 단일 책임 원칙 구현
    AddOperator addOperator;
    SubtractOperator subtractOperator;
    MultiplyOperator multiplyOperator;
    DivideOperator divideOperator;
    ModOperator modOperator;

    //2-9 생성자로 초기화해라
    public ArithmeticCalculator() {
        addOperator = new AddOperator();
        subtractOperator = new SubtractOperator();
        multiplyOperator = new MultiplyOperator();
        divideOperator = new DivideOperator();
        modOperator = new ModOperator();
    }

    public double calculate(double num1 , double num2, char operater) throws Exception
    {
        double result = 0;
        switch (operater)
        {
            case '+':
               result = addOperator.operate(num1,num2);
                break;
            case '-':
                result = subtractOperator.operate(num1,num2);
                break;
            case '*':
                result = multiplyOperator.operate(num1,num2);
                break;
            case '/':
                if (num2 == 0)
                {
                    throw new ArithmeticException("두번째 입력값은 0이 될 수 없습니다.");
                }
                else
                {
                   result = divideOperator.operate(num1,num2);
                }
                break;
            case '%' :
                result = modOperator.operate(num1,num2);
                break;
            default:
                throw new ArithmeticException("연산자 에러입니다");
        }
        return result;
    }
}

이건 진짜 단일한 책임임

 

그외 단일 책임의 원칙을 위배한게 있을까?

app클래스에서

사용자 입력과, 계산기가 나뉘는 부분등에 의해 단일클래스 원칙이 위배된다고 생각된다

Calculator클래스에서

클래스 명만봤을때는 이 클래스는 계산을 하는 로직이구나 싶을수 있다

하지만 열어봤을때 저장, 삭제, 조회기능만 담겼다.

어.. 이건 단일클래스 원칙은 아니고.. 결과 관리라는 기능을 수행하니 괜찮은거 아닌가 싶고

엄밀하게 단일 기능이라면 셋다 분리하는게 맞겠지만, 사람들이 관리라고 생각했을때 crud가 있다고 생각은 할것이다.

 

10 나눗셈 클래스 추가

근데 나눗셈 연산을 추가하기에는 기능이 추가되면 그와 연관한 메인, calculator를 갈아끼워야한다.

 SOLID중 OCP에 해당하는것이다. 

간단하게 확장에는 열려있어야하며 수정에는닫혀있어야 한다라는뜻인데

그말은 즉슨 클래스를 추가할수는있어도, 그 추가한 클래스로 인해 다른 클래스를 수정하거나 정리하는건 좋지않다.. 라는것이다

클래스에서 공통된 필드와 메서드를 묶어서 만든 추상 클래스가 그것을 해결 할 좋은 예이다

 

여기서 오칙연산이 묶을수있는 공통된 내용은 어떤것일까

매개변수로 a와 b를 받는다는것이다

추상클래스는 나를 상속받는 클래스는 이런 기능을 공통적으로 가지고 있다. 라고하는 클래스이므로

상속받는 클래스는 꼭 추상 클래스에 구현된 추상메서드를 구현해야한다.

계산을 수행하는 calculator은 추상클래스만 사용을 하면 되므로, 코드의 변형이 없이 추가를 할 수 있는것이다.

 

인터페이스와 추상클래스중 어떤게 좋은가

챗지피티가 말해준 내용이다

인터페이스는 하나의 클래스가 여러 인터페이스를 구현하고, 여러클래스가 동일한 기능이다

추상클래스는 여러 클래스가 공통의 기능을 공유하되, 일부기능은 각 클래스가 구현

 

물론 챗지피티는 인터페이스를 추천하긴 했지만, 내가 보기에는 여러 클래스가 공통적인 기능에서 내가 짠 코드는 모든 연산자 클래스에서 두개의 매개변수를 받고 리턴하는것을 볼 수 있다.

 

근데 또 구현을 하다가 생각난 부분이 있다.

여기서 추상 메서드로 구현을 하였다.

 

 

하지만 여기서 개방 폐쇄의 원칙을 지키려면 우리가 모듈러 연산을 생성하였을때 위 코드에다가 모듈러연산을 넣으면 안된다.

왜냐하면 확장에는 열려있지만 수정에는 닫혀있는 원리이기 때문이다

팀원 분과의 회의를 거쳤다. 

서로 모듈러연산을 추가하는 방법을 제외하고, 어떻게 구현 할 수 있을까.

서로 나온 공통적인 대답은, 분기점 밖에는 없다고 생각되었고 더이상 진행되지 않아서 튜터님을 찾았다

 

튜터님의 해답은 배운내용을 집합하는 과정이니까 써보라고하셨다
뭐 좋고 나쁘고 그런걸 따지는것보단, 이걸 사용해서 구현할 수 있을까? 를 보는과정이라고 하셨다
물론 튜터님도 위 과제를 해결하면서 SOLID의 원칙을 구현하기 엄청 힘들다고 하셨다
일단 고찰의 흔적을 써놓으라고 하셨다
지금 이 코드를 유지보수의 개념을 생각하고 고찰을 써놓으면 좋다고 하셨다

글쓰는 실력보소 하셨다 무한반복 ㄷㄷ

 

일단 튜터님들의 솔루션을 바탕으로 구현을 해보려고한다.

 

작성을 하면서 고민을한게
추상클래스에 연산자도 넣어야할까 고민을 하였지만
이미 기능이 명확히 나뉘어진(덧셈만을 수행하는 addoperator, etc..)가 있는데 굳이 연산자는 이곳에서 받을 필요가 없어보였다.

 

방법 1. 따로 인터페이스등을 정의해서 달수있을까?

추상클래스와 별 다를거 없는 현재 상황에서 인터페이스로 바꿔도 별 달라지는 건 없어 보인다

 

방법 2. excute 같은 메서드를 사용해서 옮기는 방법이 있지 않을까
excute를 하려면 문자(열)로 받아야할건데 그걸 변환시킬 방법이 없을까?

시도를 해봤는데 실패했다

위 방법을 사용할래도 어차피 조건에서 추가가되어야한다..

 

방법 3 메서드에 num num op를 집어넣을까?
op는 char형이나 stiring이기떄문에 그걸 연산자로 바꾸는 방법이 있어야하는데 내 수준에서는 그런 꼴을 본적이 없다

 

방법4. ch를 연산자로 변환해서 뿅 시키는 방법이 있지않을까?

 친구가 알려준 전설의 검색 단어

how to를 이용해 직접 뒤져봤다 :site필수

 

https://stackoverflow.com/questions/4832933/performing-math-operation-when-operator-is-stored-in-a-string

 

Performing math operation when operator is stored in a string

I have 2 integers: int first= 10; int second = 20; and a string representing the operation (one of +, -, /, or *): String op = "+"; How can I get the result of 10 + 20 in this example?

stackoverflow.com

 

놀랍게도 이론상 자바스크립트 엔진을 빌려와서 계산을 하는 방식이 있다곤 한다

하지만 우리 프로젝트는 jdk가 17이라서 jdk7에서 사용하는 문법은 통하지 않았다..

 

방법 5. +문자가아닌 +연산자의 유니코드를 사용 할 수 있지않을까.

모든 문자는 유니코드로 만들수있다. 유니코드를 사용할 수 있지않을까

싶었지만, 사실 유니코드는 프로그래밍 용도가 아닌 문자 자체를 표현하려는 문서이다

따라서... +연산자와 +문자를 나눠놓는 일은 없었다ㅏ..

 

방법 6 정말로 방법이 없는건가!

없다! 컴파일 시점에 연산자는 정해진다고 한다

거의 8시부터 지금까지 5시간을 뒤져봤지만 뾰족한 답을 찾을순 없었다

 

이래서 튜터님께서 구글링 실력 늘리라고 하셨구나..

 

연산자는 컴파일 시점에 정해진다고 하는데....

컴파일러는 우선 소스코드를 분석해 토큰을 나눈다, 자바의  연산자, 지정어 같은 내용을 미리 구분한다

구문 분석기 단계에서 토큰들을 받아 오류를 체크하고 문장 구조를 생성한다고 한다

그다음 연산자와 피연산자가 자바에 맞는 구문인지 검사를 한다음

구문트리를 만든다고한다.

그외 다른과정을 거쳐서 소스코드가 기계어로 번역이된다고 한다.

 

 

자바에서 연산자를 강제로 바꿀수 없는 이유는 보안때문일수도 있다고 챗지피티는 말했다

만약 내가 계좌를 이체했는데 *30000이라고 이체를 했다고 가정하자..
그값이 *30000이면 내가 가진 금액에 30000을 곱할 수 있다고 하는데

 

솔직히 위 설명도 지피티의 말돌리기인것같다..

 

그래서 물어봤다

그래서 물어봤다

 

돌아오는 답변은 니가 그걸 안다고해서 뭐가 달라지겠는데 였다

음.. 깨달음???

어떤 프로젝트고 어떤 목적을 가지고있는지 말하고싶지만

영어 못하니까 참는다..

 

Java에서는 정적 언어의 특성과 타입 시스템의 한계로 인해 문자(characters)를 런타임에 연산자(operators)로 변환할 수 없습니다.

라고 정도만 알아두자

구현은 그냥 SWITCH문으로만 

 

참고자료

https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.1

 

Chapter 15. Expressions

class Point { int x, y; } class ColoredPoint extends Point { int color; } class Test { static int test(ColoredPoint p) { return p.color; } static String test(Point p) { return "Point"; } public static void main(String[] args) { ColoredPoint cp = new Colore

docs.oracle.com

https://velog.io/@yeonheedong/CH11.3

 

[컴파일러 입문] CH1_1.3

컴파일러는 고급 언어로 쓰여진 프로그램을 어떤 특정한 컴퓨터에서 직접 실행 가능한 형태의 프로그램으로 번역해 주는 컴퓨터 프로그램이다.컴파일러의 구조는 크게 전단부(front-end)와 후단

velog.io

 

 


오늘의 회고

되게 이 문제에대해서 고민을 많이한거같다
결론은 내 수준에서는 구현하지 못할 내용같았다
지금 자바 강의라서 그나마 이렇게 쏟을 시간이 있던거지
스프링을 들어가면 이런 깊은생각은 좀 주말에 시간날때 정리하는걸로 하자
학교에 있을때는 왜 안했니 ㅠㅠ
지금이라도 잘하란뜻인가..


해야할일

1. 자바 강의 복습 + 모,, 모던자바..
2. 자바 과제 3주차.
3. 객체지향 SOLID
4. 원시타입과 래퍼타입의 차이점과 원시타입을 쓰는 이유

5. sql with, union 공부하기

 


12시간 몰입했는가?

오전에는 집중하지 못하고 팀원이랑 이런저런 얘기했는데
친밀해지는게 좋은거니까

'TIL' 카테고리의 다른 글

20240730 본캠프 12일차 TIL  (0) 2024.07.30
20240729 본캠프 11일차 TIL  (0) 2024.07.29
20240725 본캠프 9일차 TIL  (0) 2024.07.25
20240724 본캠프 8일차 TIL  (0) 2024.07.24
20240723 본캠프 7일차 TIL  (0) 2024.07.23