'4월 30일' 열두 번째 기록 [TIL]

가은·2024년 4월 30일
0

I Learned [본 캠프]

목록 보기
16/135
post-thumbnail

👩‍🏫 오늘의 출석

❓열두 번째, 9 to 9을 해 본 소감❓

오늘은 기다리던 모니터가 온다는 소식에 신나게 하루를 시작했다. 내일 드디어 과제를 제출하는 날이어서 오늘 과제를 마무리했는데 노력하는데도 여전히 부족한 나의 실력에 오늘도 여전히 막막한 기분이 들었는데 심화 OT 강의를 듣는데 튜터님꼐서 그러셨다. 다들 그러는 거고, 이상한 게 아니라고. 모두가 그런 상황이라고. 그러니 이론을 공부하고 여러 코드를 보며 코드 작성 실력을 늘려 가면 된다고 하셨다. 전공자임에도 불구하고 LEVEL 2부터 어떻게 손을 대야 할지, 코드를 어떻게 짜야 할지 막막하고 너무 부끄러울 지경이었는데 튜터님의 말씀에 오늘도 이렇게 힘을 얻고 나아간다. 오늘 모니터도 새로 받았겠다! 내일부터 잘 활용해서 열심히 해야지!

📑오늘 학습한 내용

9시부터 10시까지는 알고리즘 코드카타 시간을 가졌다.

🧩오늘의 알고리즘 : 짝수의 합🧩

/*java*/
class Solution {
    public int solution(int n) {
     int sum = 0;
        for (int i = 2; i <= n; i += 2) {
            sum += i;
        }
        return sum;
            
        }
    }
#python
def solution(n):
    total_sum = 0
    even_numbers = []
    
    for i in range(2, n + 1, 2):
        total_sum += i
        even_numbers.append(str(i))
    
    return total_sum

🧩 오늘의 SQL : 이름이 있는 동물의 아이디 🧩

SELECT ANIMAL_ID
FROM ANIMAL_INS 
WHERE NAME IS NOT NULL 
ORDER BY ANIMAL_ID ASC

❣️개인과제

✔️여섯 번째 요구사항

  • Calculator 인스턴스를 생성(new)할 때 생성자를 통해 연산 결과를 저장하고 있는 컬렉션 필드가 초기화 되도록 수정합니다.
/*App class*/
  // 초기 결과 값으로 사용할 리스트 생성
        List<Double> initialResults = Arrays.asList(0.0, 0.0); // 예시로 0.0으로 초기화

        // Calculator 인스턴스 생성 시 초기 결과 값 리스트 전달
        Calculator calculator = new Calculator(initialResults);
        
         /*       // Calculator 인스턴스에서 계산 결과 검색
        List<Double> calculationResults = calculator.getResults();
        // 초기화 확인
        if (initialResults.equals(calculationResults)) {
            System.out.println("Calculator 인스턴스가 초기 결과로 성공적으로 생성되었습니다.");
        } else {
            System.out.println("오류: Calculator 인스턴스가 초기 결과로 올바르게 초기화되지 않았습니다.");
        }
*/
/*Calculator class*/
 private List<Double> results;

    // Calculator 클래스의 생성자
    public Calculator(List<Double> initialResults) {
        this.results = new ArrayList<>(initialResults);
    }
    switch (operator) {
            case '+' -> result = num1 + num2;
            case '-' -> result = num1 - num2;
            case '*' -> result = num1 * num2;
            case '/' -> {}
            default ->

✔️일곱 번째 요구사항

    1. Calculator 클래스에 반지름을 매개변수로 전달받아 원의 넓이를 계산하여 반환해주는 메서드를 구현합니다.
    • APP 클래스의 main 메서드에 Scanner를 활용하여 사칙연산을 진행할지 원의 넓이를 구할지 명령어를 입력 받은 후 원의 넓이를 구하는 것을 선택했을 때 원의 반지름을 입력 받아 원의 넓이를 구한 후 출력되도록 구현합니다.
      • 기존에 구현되어있던 사칙연산 기능은 수정 후에도 반드시 이전과 동일하게 동작해야합니다.
    • 이때, static, final 키워드를 활용할 수 있는지 고민한 후 활용 해봅니다.
      • 반드시 static, final 키워드에 대한 설명과 활용한 이유에 대해 주석으로 작성합니다.
    • 원의 넓이 결과를 저장하는 컬렉션 타입의 필드 선언 및 생성
      • 계산된 원의 넓이를 저장합니다.
      • 생성자로 초기화됩니다.
      • 외부에서 직접 접근할 수 없습니다.
      • Getter, Setter 메서드를 구현합니다.
      • 원의 넓이 결과값들을 조회하는 메서드를 구현합니다.
/*App clss*/
while (true) {
            System.out.println("작업을 선택하세요: ");
            System.out.println("1. 산술 연산 수행");
            System.out.println("2. 원의 넓이 계산");
            System.out.println("3. 저장된 연산 결과 보기");
            System.out.println("4. 저장된 원의 넓이 결과 보기");
            System.out.print("선택: ");
            int choice = sc.nextInt();

            switch (choice) {
                case 1:
                    performArithmetic(calculator, sc);
                    break;
                case 2:
                    calculateCircleArea(calculator, sc);
                    break;
                case 3:
                    showResults(calculator.inquiryResults());
                    break;
                case 4:
                    showResults(calculator.inquiryCircleAreas());
                    break;
                default:
                    System.out.println("잘못된 선택입니다. 1, 2, 3 또는 4를 입력하세요.");
            }

            System.out.println("계속 하시겠습니까? (종료하려면 'exit' 입력)");
            String text = sc.next();
            if (text.equals("exit")) {
                break;
                }
        sc.close();
    }

    private static void performArithmetic(Calculator calculator, Scanner sc) {
        System.out.println("첫 번째 숫자를 입력하세요: ");
        double firstNum = sc.nextDouble();
        System.out.println("두 번째 숫자를 입력하세요: ");
        double secondNum = sc.nextDouble();
        System.out.print("연산자를 입력하세요 (+, -, *, /): ");
        char operator = sc.next().charAt(0);
        try {
            double result = calculator.calculate(firstNum, secondNum, operator);
            System.out.println("결과: " + result);
        } catch (CalculatorException e) {
            System.out.println("오류: " + e.getMessage());
        }
    }

    private static void calculateCircleArea(Calculator calculator, Scanner sc) {
        System.out.println("원의 반지름을 입력하세요: ");
        double radius = sc.nextDouble();
        double area = calculator.calculateCircleArea(radius);
        System.out.println("원의 넓이: " + area);
    }

    private static void showResults(List<Double> results) {
        System.out.println("저장된 결과: " + results);
/*Calculator class*/
   private List<Double> results; // 연산 결과를 저장하는 컬렉션 타입 필드
   private List<Double> circleAreas; // 원의 넓이 결과를 저장하는 컬렉션 타입 필드
   
    // Calculator 클래스의 생성자
    public Calculator(List<Double> initialResults) {
        this.circleAreas = new ArrayList<>(); // 원의 넓이 결과를 저장하는 컬렉션 초기화
    }
   / 원의 넓이를 계산하고 결과를 반환하는 메서드
    public double calculateCircleArea(double radius) {
        double area = Math.PI * radius * radius;
        circleAreas.add(area); // 원의 넓이 결과를 컬렉션에 저장
        return area;
    }
    // 원의 넓이 결과 리스트를 반환하는 메서드
    public List<Double> inquiryCircleAreas() {
        return new ArrayList<>(circleAreas);
    }

✔️여덟 번째 요구사항

  • 사칙연산을 수행하는 계산기 ArithmeticCalculator 클래스와 원과 관련된 연산을 수행하는 계산기 CircleCalculator 클래스 2개를 구현합니다.
    • 기존에 만들어둔 Calculator 클래스를 수정합니다
    • 수정한 Calculator 클래스를 활용하여 ArithmeticCalculator, CircleCalculator 클래스를 구현 해봅니다. (상속)
    • 위 요구사항을 구현하게되면 App 클래스의 main 메서드에 오류가 발생할 겁니다.
      • 구현한 클래스들을 활용하여 오류가 발생하지 않고 활용될 수 있도록 수정 해보세요!
      • 기존에 사칙연산을 저장하던 컬렉션 필드의 타입을 Double로 변경해도 괜찮습니다.
      • 필드의 접근 제어자를 변경해도 괜찮습니다.
/*App class*/
 // 초기 결과값 리스트 생성
        List<Double> initialResults = new ArrayList<>(Arrays.asList(0.0, 0.0));
        // ArithmeticCalculator 및 CircleCalculator 객체 생성
        ArithmeticCalculator arithmeticCalculator = new ArithmeticCalculator(initialResults);
        CircleCalculator circleCalculator = new CircleCalculator(initialResults, initialResults);
         switch (choice) {
                case 1:
                    // 산술 연산 수행 메소드 호출
                    performArithmetic(arithmeticCalculator, sc);
                    break;
                case 2:
                    // 원의 넓이 계산 메소드 호출
                    calculateCircleArea(circleCalculator, sc);
                    break;
                case 3:
                    // 저장된 연산 결과 보기
                    showResults(arithmeticCalculator.inquiryResults());
                    break;
                case 4:
                    // 저장된 원의 넓이 결과 보기
                    showResults(circleCalculator.inquiryCircleAreas());
                    }
           private static void performArithmetic(ArithmeticCalculator calculator, Scanner sc) {}
/*ArithmeticCalculator class*/
public class ArithmeticCalculator extends Calculator {
    public ArithmeticCalculator(List<Double> initialResults) {
        super(initialResults);
    }

    @Override
    // 산술 연산을 수행하고 결과를 반환하는 메소드
    public double calculate(double num1, double num2, char operator) throws CalculatorException {
        double result;
        switch (operator) {
            case '+' -> result = num1 + num2; // 덧셈
            case '-' -> result = num1 - num2; // 뺄셈
            case '*' -> result = num1 * num2; // 곱셈
            case '/' -> {
                // 나눗셈 시 예외 처리
                if (num2 == 0) {
                    throw new CalculatorException("Cannot divide by 0."); // 0으로 나눌 수 없음
                }
                result = num1 / num2; // 나눗셈 수행
            }
            default -> throw new CalculatorException("Invalid operator symbol."); // 잘못된 연산자 기호
        }
        results.add(result); // 결과를 리스트에 추가
        return result; // 결과 반환
    }
}
/*Calculator class*/
public class Calculator {
    protected List<Double> results; // 서브클래스에서 접근할 수 있도록 protected로 변경
/*CircleCalculator*/
public class CircleCalculator extends Calculator {
    private List<Double> circleAreas; // 원의 넓이를 저장하는 리스트

    public CircleCalculator(List<Double> initialResults, List<Double> initialCircleAreas) {
        super(initialResults);
        this.circleAreas = initialCircleAreas;
    }

    // 원의 넓이를 계산하고 리스트에 추가하는 메소드
    public double calculateCircleArea(double radius) {
        double area = Math.PI * radius * radius; // 원의 넓이 계산
        circleAreas.add(area); // 계산된 넓이를 리스트에 추가
        return area;
    }

    // 저장된 원의 넓이를 조회하는 메소드
    public List<Double> inquiryCircleAreas() {
        return circleAreas;
    }
}

✔️아홉 번째 요구사항

  • ArithmeticCalculator 클래스의 연산 메서드에 책임(역할)이 많아 보입니다. 사칙연산 각각의 기능을 담당하는 AddOperator, SubtractOperator, MultiplyOperator, DivideOperator 클래스를 만들어 연산 메서드의 책임을 분리 해봅니다. (SRP)
    • Calculator 클래스에 사칙연산 클래스들을 어떻게 활용할 수 있을지 고민 해봅니다. (포함 관계)
    • 활용 방법을 찾아 적용했을 때 사칙연산 클래스들을 초기화 해야하는데 이때, 반드시 생성자를 활용해 봅니다.
    • 마찬가지로 ArithmeticCalculator 클래스의 연산 메서드를 수정 하더라도 이전과 똑같이 동작해야합니다.
/*AddOperator class*/
// 덧셈 연산을 수행하는 AddOperator 클래스
class AddOperator implements Operator {
    @Override
    public double calculate(double num1, double num2) {
        return num1 + num2;
    }
}
/*ArithmeticCalculator class*/
/ 연산자 인터페이스: calculate 메소드를 정의함
interface Operator {
    double calculate(double num1, double num2) throws CalculatorException;
}

// 산술 연산을 위한 ArithmeticCalculator 클래스
public class ArithmeticCalculator extends Calculator {
    private final Operator addOperator; // 덧셈 연산자
    private final Operator subtractOperator; // 뺄셈 연산자
    private final Operator multiplyOperator; // 곱셈 연산자
    private final Operator divideOperator; // 나눗셈 연산자

    // 생성자: 초기 결과 리스트를 받아와서 설정하고 연산자 객체들을 초기화함
    public ArithmeticCalculator(List<Double> initialResults) {
        super(new ArrayList<>(initialResults));
        this.addOperator = new AddOperator();
        this.subtractOperator = new SubtractOperator();
        this.multiplyOperator = new MultiplyOperator();
        this.divideOperator = new DivideOperator();
    }
    witch (operator) {
            case '+':
                result = addOperator.calculate(num1, num2); // 덧셈 연산 수행
                break;
            case '-':
                result = subtractOperator.calculate(num1, num2); // 뺄셈 연산 수행
                break;
            case '*':
                result = multiplyOperator.calculate(num1, num2); // 곱셈 연산 수행
                break;
            case '/':
                result = divideOperator.calculate(num1, num2); // 나눗셈 연산 수행
                break;
            default:
                throw new CalculatorException("Invalid operator symbol."); // 잘못된 연산자 기호
/*CircleCalculator class*/
initialCircleAreas) {
        this.circleAreas = new ArrayList<>(initialCircleAreas);
    }
/*DivideOperator class*/
// 나눗셈 연산을 수행하는 DivideOperator 클래스
class DivideOperator implements Operator {
    @Override
    public double calculate(double num1, double num2) throws CalculatorException {
        if (num2 == 0) {
            throw new CalculatorException("Cannot divide by 0."); // 0으로 나눌 수 없음
        }
        return num1 / num2;
    }
}
/*MultiplyOperator class*/
// 곱셈 연산을 수행하는 MultiplyOperator 클래스
class MultiplyOperator implements Operator {
    @Override
    public double calculate(double num1, double num2) {
        return num1 * num2;
    }
}
/*SubtractOperator class*/
// 뺄셈 연산을 수행하는 SubtractOperator 클래스
class SubtractOperator implements Operator {
    @Override
    public double calculate(double num1, double num2) {
        return num1 - num2;
    }
}

✔️열 번째 요구사항

    1. ArithmeticCalculator 클래스에 추가로 나머지 연산(%) 기능을 추가하기 위해 ModOperator 클래스를 만들어 추가합니다.
    • 추가하려고 하니 앞으로 계속 기능이 추가되면 여러 부분의 소스코드를 수정해야 한다는 생각이 들었고 “현재 비효율적인 구조가 아닌가?” 라는 의구심이 들었습니다.
      • 따라서 소스 코드의 변경은 최소화하면서 기능을 쉽게 추가(확장)할 수 있는 방법을 고민 해봅니다. (OCP)
    • 방법을 고민 및 학습하여 적용했을 때 전체적인 소스 코드와 구조의 변경이 발생 했을 겁니다.
      • 최대한 생각한 방법으로 구현 해보세요. 틀린 답은 없습니다. 컴파일에 문제가 없고 기능이 정상적으로 동작 하면 모두 정답입니다.
      • 포기하는 것 보다 본인이 생각한데로 구현해보고 다른 개발자들과 공유 하면서 여러 가지 방법들을 확인 했을 때 실력이 가장 많이 향상됩니다.
    • 마찬가지로 수정 후에도 이전과 똑같이 동작해야합니다.
/*ArithmeticCalculator class*/
private final ModOperator modOperator; // 나머지 연산자

public ArithmeticCalculator(List<Double> initialResults) {
        super(new ArrayList<>(initialResults));
        this.addOperator = new AddOperator(); // 덧셈 연산자 초기화
        this.subtractOperator = new SubtractOperator(); // 뺄셈 연산자 초기화
        this.multiplyOperator = new MultiplyOperator(); // 곱셈 연산자 초기화
        this.divideOperator = new DivideOperator(); // 나눗셈 연산자 초기화
        this.modOperator = new RemainderOperator(); // 나머지 연산자 초기화
    }
    switch (operator){
     case '%':
                result = modOperator.calculate(num1, num2); // 나머지 연산 수행
    }
/*RemainderOperator class*/
// 나머지 연산을 나타내는 ModOperator 인터페이스
interface ModOperator {
    double calculate(double num1, double num2) throws CalculatorException;
}

// RemainderOperator 클래스는 ModOperator 인터페이스를 구현하여 나머지 연산 처리
class RemainderOperator implements ModOperator {
    @Override
    // 나머지 연산을 수행하는 calculate 메소드
    public double calculate(double num1, double num2) throws CalculatorException {
        // 0으로 나누는 경우 예외 처리
        if (num2 == 0) {
            throw new CalculatorException("0으로 나눌 수 없습니다. 다시 입력하세요."); // 0으로 나눌 수 없음
        }
        return num1 % num2; // 나머지 연산 수행
    }
}

💻자바의 정석 내용정리

여러 종류의 객체를 배열로 다루기

  • 조상타입의 배열에 자손들의 객체를 담을 수 있음
/*1번 코드*/
Product p1 = new Tv();
Product p2 = new Computer();
Product p3 = new Audio();

/*1번 코드를 조상 타입의 배열에 자손들을 객체를 담을 수 있도록 수정*/
Product p[] = new Product[3];
p[0] = new Tv();
p[1] = new Computer();
p[2] = new Audio();

위의 코드를 그림으로 표현한 것

추상 클래스

  • 미완성 설계도
    - 미완성 메서드를 갖고 있는 클래스
  • 다른 클래스 작성에 도움을 주기 위한 것
    - 인스턴스 생성 불가
    • 상속을 통해 추상 메서드를 완성해야 인스턴스 생성 가능
  • 추상화된 코드는 구체화된 코드보다 유연함
    - 변경에 유리함
abstract class Player {					// 추상 클래스
	abstract void play(int pos);		// 추상 메서드
    abstract voud stop();				// 추상 메서드
}

class AudioPlayer extends Player {		// 완전 클래스
	void play(itn pos) {/*내용*/}			// 추상 메서드 구현
    void stop() {/*내용*/}				// {} 구현부 작성
}

abstract class AbstractPlayer extends Player {
	void play(int pos) {/*내용*/}			// 추상메서드 구현
    /*추상 클래스에 있던 추상 메소드 2개중 1개만 작성하였기 때문에 클래스 앞에 abstract 붙여줘야 함*/
}

추상 메서드

  • 미완성 메서드
    - 선언부는 있지만 구현부 {}가 없는 메서드
    • 메서드는 선언부만 알면 호출 가능하므로 추상 메서드도 호출 가능!
  • 꼭 필요하지만 자손마다 다르게 구현될 것으로 예상되는 경우 사용
  • 주석을 통해 어떤 기능을 수행할 목적으로 작성하였는지 설명
    - abstract 리턴타입 메서드이름();
abstract class Player {
	boolean pause;			// 일시정지 상태를 저장하기 위한 변수 (iv)
    int currentPos;			// 현재 paly되고 있는 위치를 저장하기 위한 변수 (iv)
    
    Player() {				// 생성자
    	pause = flase;
        curtentPos = 0;
    }
    /*지정된 위치에서 시작하는 기능이 수행하도록 작성해야함*/
    abstract void play(int pos);		// 추상 메서드
    /*재생을 즉시 멈추는 기능을 수행하도록 작성해야 함*/
    abstract void stop();				// 추상 메서드
    
    void play() {			// 인스턴스 메서드(1. 객체 생성 후 2. 호출)
    	play(currentPos);			// 추상 메서드 사용 가능
    }
}

GIT&GITHUB 심화 강의

브랜치를 생성하고 이동하는 방법과 머지, 그리고 기본적으로 팀 프로젝트 시에 깃허브를 어떻게 사용하면 좋을지에 대한 강의를 들었다.

0개의 댓글