클래스와 객체의 개념

    클래스(Class)란?

    객체를 생성하기 위한 설계도(템플릿)

    즉, 속성(필드)와 동작(메서드)을 정의하는 툴

     

    클래스 정의

    class Car {
        String brand; // 속성 (필드)
        int speed;
    
        void accelerate() { // 동작 (메서드)
            speed += 10;
            System.out.println(brand + "가 속도를 올립니다. 현재 속도: " + speed);
        }
    }

    객체(Object)란?

    클래스를 기반으로 생성된 실체(인스턴스)

    즉, 클래스에서 정의한 속성과 동작을 실제로 가지고 있는 개별 데이터

     

    객체 생성

    public class Main {
        public static void main(String[] args) {
            Car myCar = new Car();  // 객체 생성
            myCar.brand = "Tesla";  // 속성 값 설정
            myCar.speed = 0;
            
            myCar.accelerate(); // 동작 수행
        }
    }

     

    ➡︎ myCarCar 클래스로부터 만들어진 객체!

    ➡︎ 개별 객체에 속성을 설정할 수 있음 (myCar.brand = "Tesla")


    객체를 사용하는 이유

    1. 코드의 재사용성 증가
      • 클래스를 한 번 정의하면 여러 객체를 생성할 수 있음
      • 같은 구조를 가진 객체를 만들 때 중복 코드를 줄일 수 있음
    2. 유지보수성 향상
      • 코드가 모듈화되므로, 특정 기능을 수정할 때 다른 부분에 영향을 줄 가능성이 낮아짐
      • 관련 기능을 묶어 가독성이 향상됨
    3. 캡슐화 및 정보 은닉 가능
      • 객체 내부의 데이터를 보호하고, 불필요한 접근을 제한할 수 있음
      • 외부에서는 제한된 방식으로만 데이터를 변경할 수 있도록 제어 가능

    캡슐화

    캡슐화(Encapsulation)란?

    객체의 내부 데이터를 외부에서 직접 접근하지 못하도록 보호하는 개념

    ➡︎ 데이터 보호 + 객체 내부 구현 숨기기 가능


    접근 제어자(Access Modifier)

    Java 에서는 접근 제어자를 사용해 데이터 접근 범위를 제한할 수 있음

    • private: 클래스 내부에서만 접근 가능, 가장 제한적
    • protected: 같은 패키지 또는 상속 관계에서 접근 가능
    • public: 어디서든 접근 가능, 가장 개방적

     

    캡슐화 적용

    class BankAccount {
        private int balance = 0; // private으로 직접 접근 불가
    
        public void deposit(int amount) { // 외부에서는 public 메서드로 접근
            if (amount > 0) {
                balance += amount;
                System.out.println("입금 완료! 현재 잔액: " + balance);
            }
        }
    
        public int getBalance() { // 잔액 조회 메서드
            return balance;
        }
    }

     

     

    캡슐화된 객체 사용

    public class Main {
        public static void main(String[] args) {
            BankAccount account = new BankAccount();
            account.deposit(1000);
            
            System.out.println("현재 잔액: " + account.getBalance());
        }
    }

     

    ➡︎ balance 필드는 private 이므로 외부에서 직접 접근 불가

    ➡︎ deposit() 메서드를 통해서만 잔액 변경 가능! ⭐️ 데이터 무결성 유지 ⭐️


    주요 포인트

    • 클래스와 객체의 차이를 명확히 알아야 함!
      • 클래스: 객체를 만들기 위한 설계도
      • 객체: 클래스를 기반으로 생성된 실체
    • 객체를 사용하는 이유를 코드 재사용성, 유지보수성, 캡슐화 관점에서 논리적으로 설명할 줄 알아야 함!
      • 코드 재사용성 증가
      • 유지보수성 향상
      • 캡슐화를 통한 정보 보호
    • 캡슐화접근 제어자와 실제 활용 예시를 알고 있어야 함!
      • 객체 내부 데이터를 외부에서 직접 접근하지 못하게 보호
      • private, public 등의 접근 제어자를 사용

     

    [Level2] 프로세스

     

    프로그래머스

    SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

    programmers.co.kr

     

    문제 이해

    슈도 코드

    scoville 배열 -> 우선순위 큐
    int count = 0;
    scoville.peek() >= k -> return count;
    반복:
    	오름차순 정렬
    	count++;
    	scoville.poll() + (scoville.poll() * 2) >= k
    	-> break;
    	else scoville.add();
    
    
    // GPT
    1. 우선순위 큐(PriorityQueue)를 생성하고 scoville 배열의 모든 원소를 추가한다.
    2. count(섞은 횟수)를 0으로 초기화한다.
    3. 만약 최솟값(큐의 peek)이 K 이상이면 count를 반환하고 종료한다.
    4. 반복문 시작 (큐의 크기가 2 이상일 동안 반복):
        4.1. count를 1 증가시킨다.
        4.2. 가장 작은 값(첫 번째 poll)과 두 번째로 작은 값(두 번째 poll)을 꺼낸다.
        4.3. 두 개의 값을 섞어서 새로운 값을 만든다: newScoville = first + (second * 2)
        4.4. 만약 newScoville이 K 이상이면 count를 반환하고 종료한다.
        4.5. 그렇지 않으면 newScoville을 큐에 추가한다.
    5. 반복이 끝난 후, 남아있는 값이 K 이상이면 count를 반환하고, 그렇지 않으면 -1을 반환한다.

    참고한 부분

    // 변경 전 (몇 개의 테스트케이스 실패)
    if (sc < K) pQueue.add(sc);
    // 변경 후
    pQueue.add(sc);
    
    // -> K 미만일 경우에만 우선순위 큐에 다시 추가하는 게 아니라 무조건 추가해야 함.

    전체 코드

    import java.util.*;
    
    class Solution {
        public long solution(int[] scoville, int K) {
            long answer = 0;
            PriorityQueue<Integer> pQueue = new PriorityQueue<>();
            for (int s: scoville) {
                pQueue.add(s);
            }
            
            while (pQueue.size() > 1) {
                if (pQueue.peek() >= K) return answer;
                int sc = pQueue.poll() + (pQueue.poll() * 2);
                pQueue.add(sc);
                answer++;
            }
            
            if (!pQueue.isEmpty() && pQueue.peek() < K) {
                answer = -1;
            }
            return answer;
        }
    }

     

    [Level2] 프로세스

     

    프로그래머스

    SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

    programmers.co.kr

     

    문제 이해

    → 프로세스의 값이 아님 위치로 판단해야 함

    슈도 코드

    1. 큐(queue)와 우선순위(priority queue)를 초기화한다.
       - queue: (인덱스, 우선순위) 형태로 저장
       - priorityQueue: 우선순위 값들만 저장 (내림차순 정렬)
    
    2. 반복문을 실행하면서 다음을 수행:
       - queue에서 (현재 인덱스, 현재 우선순위)를 poll()
       - 현재 우선순위가 priorityQueue에서 가장 높은 값과 같은지 비교:
         - 같다면 실행 (answer += 1)
         - 목표 인덱스이면 종료하고 answer 반환
         - 다르면 다시 queue에 추가

    참고한 부분

    // 큐에 배열로 저장 가능
    Queue<int[]> queue = new LinkedList<>();
    queue.add(new int[]{i, priorities[i]});
    
    
    // 우선순위 큐
    // 기본형: 우선순위가 낮은 숫자 먼저 (오름차순)
    PriorityQueue<Integer> pQueue = new PriorityQueue<>();
     
    // 우선순위가 높은 숫자 먼저(내림차순)
    PriorityQueue<Integer> pQueue = new PriorityQueue<>(Collections.reverseOrder());

     

    전체 코드

    import java.util.*;
    
    class Solution {
        public int solution(int[] priorities, int location) {
            int answer = 0;
            Queue<int[]> queue = new LinkedList<>();
            PriorityQueue<Integer> pQueue = new PriorityQueue<>(Collections.reverseOrder());
            
            // 큐 초기화
            for (int i = 0; i < priorities.length; i++) {
                queue.add(new int[]{i, priorities[i]});
                pQueue.add(priorities[i]);
            }
            
            while (!queue.isEmpty()) {
                int[] top = queue.poll();
                // 우선순위가 제일 높은 값이면
                if (top[1] == pQueue.peek()) {
                    pQueue.poll();  // 실행했으므로 제거
                    answer++;  // 실행 순서 증가
                    // 현재 인덱스가 목표 위치의 값이면 return
                    if (top[0] == location) {
                        return answer;
                    }
                } else {
                    queue.add(top);  // 우선순위가 아니면 다시 add
                }
            }
            return answer;
        }
    }

     

     

    '코딩테스트 > 프로그래머스' 카테고리의 다른 글

    [JAVA] 프로그래머스 Level2. 더 맵게  (0) 2025.03.02

    실무에서의 권장 방식

    • Create, Update는 분리하는 것이 일반적입니다.
      • Create는 대부분 필수 필드가 많고, 기본값 설정이나 추가적인 유효성 검사를 요구합니다.
      • Update는 부분 업데이트(Partial Update)를 지원해야 하는 경우가 많아, 선택적인 필드를 허용합니다.
    • Read와 Write를 분리하라 (CQRS 원칙에 따라):
      • Read용 DTO: 사용자에게 데이터를 반환할 때 최적화된 필드만 포함.
      • Write용 DTO (Create/Update): 요청 데이터를 받을 때 필요한 필드만 포함.

    ➡︎ Create, Update 요청 DTO 분리

    • CreateXxxDto: 생성 전용
    • UpdateXxxDto: 수정 전용

    ➡︎ Create, Update 응답 DTO 형식이 유사하다면 통일해도 됨

    • XxxReadResponseDto : 읽기 전용
    • XxxResponseDto : 생성/수정

     

    프로젝트 할 때마다 궁금했는데, 최종 프로젝트를 앞두고 API 설계를 하다가 찾아봤다!

    RESTful API의 본질과 설계 원칙

    RESTful API의 핵심은 다음과 같은 6가지 원칙을 따르는 것입니다:

    1. 클라이언트-서버 구조: 클라이언트와 서버가 독립적으로 동작.
    2. 무상태성(Stateless): 각 요청은 독립적이며 서버는 클라이언트 상태를 저장하지 않음.
    3. 캐시 가능(Cacheable): 응답 데이터가 캐싱 가능.
    4. 계층화(Layered System): 클라이언트-서버 간 중간 계층 존재 가능.
    5. 통합된 인터페이스(Uniform Interface): 일관된 URI와 메서드 사용.
    6. 코드 온 디맨드(Optional): 서버에서 클라이언트로 실행 가능한 코드를 보낼 수 있음.
    • RESTful APIHTTP 메서드(GET, POST, PUT, DELETE 등)를 사용하여 리소스를 관리하는 스타일을 따릅니다.
    • CRUD 중심 설계는 데이터(리소스)의 생성(Create), 조회(Read), 갱신(Update), 삭제(Delete) 작업을 API로 제공하는 설계 방식입니다.
    • 따라서, CRUD 설계는 RESTful API의 한 형태일 뿐이며, RESTful API는 더 넓은 범위를 포괄합니다.

    여태까지 RESTful API 가 CRUD 중심의 API 설계라고 생각하고 있었는데 아니었다...!

     

    DDD와 이벤트 기반 설계도 RESTful한가?

    DDD 중심 설계와 이벤트 기반 설계도 RESTful API의 기본 원칙을 지킬 수 있습니다:

    • 리소스 중심: 비즈니스 도메인 모델(포인트, 결제, 사용자 등)을 리소스로 정의.
    • HTTP 메서드: 리소스의 상태를 변경하거나 조회할 때 HTTP 메서드를 올바르게 사용.
    • 표현성: 리소스의 상태를 API 응답으로 표현.

    예를 들어, 다음 API는 RESTful하면서도 CRUD 중심이 아닙니다:

    1. POST /points/earn: 포인트 적립(도메인 중심 설계).
    2. POST /events/payment-completed: 결제 완료 이벤트 처리(이벤트 기반 설계)
    • http와 https
      • 웹에서 데이터를 전송하는 주요 프로토콜입니다
      • HTTP (HyperText Transfer Protocol)
        • 보안: 데이터가 암호화되지 않고 평문으로 전송됩니다. 이는 네트워크를 통해 전송되는 데이터가 도청, 중간자 공격 등에 취약할 수 있음을 의미합니다.
        • 포트: 기본적으로 80번 포트를 사용합니다.
        • 속도: HTTPS에 비해 약간 빠를 수 있지만, 보안이 취약합니다.
        • 사용: 보안이 크게 중요하지 않은 웹사이트에서 주로 사용됩니다.
      • HTTPS (HyperText Transfer Protocol Secure)
        • 보안: SSL/TLS(보안 소켓 계층/전송 계층 보안) 프로토콜을 사용하여 데이터를 암호화합니다. 이는 데이터의 기밀성과 무결성을 보장하며, 사용자의 개인정보와 민감한 데이터를 보호합니다.
        • 포트: 기본적으로 443번 포트를 사용합니다.
        • 속도: 암호화/복호화 과정이 필요하기 때문에 약간 느릴 수 있습니다. 그러나 현대의 컴퓨팅 능력과 최적화된 SSL/TLS 구현 덕분에 차이가 거의 느껴지지 않습니다.
        • 사용: 보안이 중요한 웹사이트(온라인 쇼핑, 뱅킹, 로그인 페이지 등)에서 필수적으로 사용됩니다.
      • 왜 HTTPS를 사용해야 하는가?
        • 데이터 보호: HTTPS는 데이터를 암호화하여 사용자의 개인 정보와 민감한 데이터를 보호합니다.
        • 신뢰성: 사용자와 웹사이트 간의 신뢰를 구축합니다. 브라우저는 HTTPS를 사용하지 않는 사이트에 대해 경고를 표시할 수 있습니다.
        • SEO 이점: 검색 엔진(특히 Google)은 HTTPS를 사용하는 웹사이트를 선호합니다. 이는 검색 순위에 긍정적인 영향을 미칠 수 있습니다.
        • 데이터 무결성: HTTPS는 데이터가 전송 중에 변조되지 않도록 보호합니다.
        • 따라서, 보안이 중요한 모든 웹사이트는 HTTPS를 사용해야 하며, 대부분의 현대 웹사이트는 기본적으로 HTTPS를 사용하고 있습니다.

    + Recent posts