Try using it in your preferred language.

English

  • English
  • 汉语
  • Español
  • Bahasa Indonesia
  • Português
  • Русский
  • 日本語
  • 한국어
  • Deutsch
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • ไทย
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar
translation

AI가 번역한 다른 언어 보기

제이온

[오브젝트] 2장. 객체 지향 프로그래밍

  • 작성 언어: 한국어
  • 기준국가: 모든 국가 country-flag

언어 선택

  • 한국어
  • English
  • 汉语
  • Español
  • Bahasa Indonesia
  • Português
  • Русский
  • 日本語
  • Deutsch
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • ไทย
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar

durumis AI가 요약한 글

  • 영화 예매 시스템을 객체 지향 프로그래밍으로 구현하는 방법을 다루며, 객체, 클래스, 협력, 인터페이스 등의 개념을 설명하고 있다.
  • 특히, 할인 정책과 할인 조건을 구현하기 위해 상속, 다형성, 추상화를 활용하는 방법을 자세히 소개하며, 영화 예매 시스템의 핵심 기능을 구현하는 예시를 보여준다.
  • 상속과 합성의 차이점을 비교 분석하고, 코드 재사용을 위한 합성의 장점과 유연한 설계를 위한 추상화의 중요성을 강조한다.

영화 예매 시스템


요구 사항 살펴보기

  • 온라인 영화 예매 시스템을 구현하려고 한다.
  • 영화는 영화에 대한 기본 정보를 표현한다.
    • 제목, 상영 시간, 가격 정보 등
  • 상영은 실제로 관객이 영화를 관람하는 사건을 표현한다.
    • 상영 일자, 시간, 순번 등
  • 사람들은 영화를 예매한다고 하지만, 사실 특정 상영되는 영화를 예매한다고 해야 옳다.
  • 할인 조건
    • 가격의 할인 여부
    • 순서 조건: 상영 순번을 이용해 할인 여부를 결정
    • 기간 조건: 영화 상영 시작 시간을 이용해 할인 여부를 결정
  • 할인 정책
    • 할인 요금을 결정
    • 금액 할인 정책: 예매 요금에서 일정 금액을 할인
    • 비율 할인 정책: 정가에서 일정 비율의 요금을 할인
  • 영화 별로 하나의 할인 정책을 할당하거나 아예 안 할 수 있고, 할인 조건은 다수의 할인 조건을 섞을 수 있다.
  • 할인 정책이 적용되어 있지만 할인 조건을 만족하지 못하거나, 할인 정책이 적용되어 있지 않은 경우에는 요금을 할인하지 않는다.


객체 지향 프로그래밍을 향해

협력, 객체, 클래스

  • 객체 지향은 객체를 지향하는 것이다.
    • 클래스를 결정한 후에 클래스에 어떤 속성과 메서드가 필요한지 고민하지 말아야 한다.
    • 어떤 객체들이 어떤 상태와 행동을 가지는지 결정해야 한다.
    • 객체를 독립적인 존재가 아니라, 협력하는 공동체의 일원으로 봐야 한다.


도메인의 구조를 따르는 프로그램 구조

  • 도메인은 문제를 해결하기 위해 사용자가 프로그램을 사용하는 분야를 말한다.

Untitled

  • 일반적으로 클래스의 이름은 대응되는 도메인 개념의 이름과 동일하거나 적어도 유사하게 지어야 한다.
  • 클래스 사이의 관계도 최대한 도메인 개념 사이에 맺어진 관계와 유사하게 만들어서 프로그램의 구조를 이해하고 예상하기 쉽게 만들어야 한다.


클래스 구현하기

  • 클래스는 내부와 외부로 구분되며 훌륭한 클래스를 설계하기 위해서는 어떤 부분을 외부에 공개하고, 어떤 부분을 감출지 결정해야 한다.
    • 객체의 속성은 private로 막고, 내부 상태를 변경하기 위해 필요한 메서드를 public으로 열어 둔다.
  • 클래스의 내부와 외부룰 구분해야 객체의 자율성을 보장함으로써 프로그래머에게 구현의 자유를 제공한다.


자율적인 객체

  • 객체는 상태와 행동을 가진 자율적인 객체여야 한다.
  • 데이터와 기능을 객체 내부로 함께 묶는 것을 캡슐화라고 한다.
  • 접근 제어를 통해 외부의 간섭을 줄여야 객체는 스스로 자기의 행동을 결정할 수 있게 된다.
  • 인터페이스와 구현의 분리 원칙은 객체 지향 프로그래밍을 위해 따라야 하는 주요 원칙이다.
    • 퍼블릭 인터페이스: 외부에서 접근 가능한 부분
    • 구현: 내부에서만 접근 가능한 부분


프로그래머의 자유

  • 프로그래머의 역할은 클래스 작성자와 클라이언트 프로그래머로 구분된다.
    • 클래스 작성자는 데이터 타입을 새로 추가
    • 클라이언트 프로그래머는 클래스 작성자가 추가한 데이터 타입을 사용
  • 구현 은닉
    • 클래스 작성자는 필요한 부분만 클라이언트 프로그래머에게 제공하여 내부 구현을 감출 수 있다.
    • 클라이언트 프로그래머는 인터페이스만 알면 되므로 지식의 양을 줄일 수 있다.


협력하는 객체들의 공동체

  • 돈을 표현할 때 단순히 Long 타입의 변수를 선언하기 보다는, Money와 같이 객체로 포장해 주는 것이 좋다. 객체를 사용하면 의미 전달이 보다 잘 되고, 중복된 연산 처리를 한 곳에서 수행할 수 있기 때문이다.
  • 시스템의 어떤 기능을 구현하기 위해 객체들 사이에 이뤄지는 상호 작용을 협력이라고 부른다.


협력에 관한 짧은 이야기

  • 객체가 다른 객체와 상호 작용할 수 있는 유일한 방법은 메시지를 전송하거나 수신하는 것이다.
  • 수신된 메시지를 처리하기 위한 자신만의 방법을 메서드라고 부른다.
  • 메시지와 메서드를 구분하는 것은 중요하며, 여기서부터 다형성의 개념이 출발한다.


할인 요금 구하기

할인 요금 계산을 위한 협력 시작하기

  • Movie 클래스에는 할인 정책에 관한 자세한 로직이 들어 있지 않고, DiscountPolicy 인터페이스에 위임하였다. 상속과 다형성, 추상화를 이용하는 것이 정말 중요하다.


할인 정책과 할인 조건

Untitled


상속과 다형성

컴파일 시간 의존성과 실행 시간 의존성

  • 코드의 의존성과 실행 시점의 의존성이 다를 수 있다.
  • 둘 간의 의존성이 다를수록 코드를 이해하기 어려워지지만, 유연하고 확장 가능한 코드가 된다.


차이에 의한 프로그래밍

  • 상속은 기존 클래스를 기반으로 새로운 클래스를 쉽고 빠르게 추가할 수 있으며, 부모 클래스의 구현을 재사용할 수 있다.
  • 부모 클래스와 다른 부분만을 추가해서 새로운 클래스를 만드는 방법을 차이에 의한 프로그래밍이라고 부른다.


상속과 인터페이스

  • 상속은 부모 클래스가 제공하는 모든 인터페이스를 자식 클래스가 물려 받게 해 준다.
  • 인터페이스는 객체가 이해할 수 있는 메시지의 목록을 정의한다.
public class Movie {

    public Money calculateMovieFee(Screening screening) {
        return fee.minus(discountPolicy.calculateDiscountAmount(screening));
    }
}
  • Movie는 DiscountPolicy에게 calculateDiscountAmount 메시지를 보내고 있다. Movie 입장에서는 어떤 클래스의 인스턴스가 응답을 주는 지는 상관 없고, 응답을 성공적으로 주기만 하면 된다.
  • 따라서 AmountDiscountPolicy와 PercentDiscountPolicy 모두 DiscountPolicy를 대신해서 Movie와 협력할 수 있다.
  • 이처럼 자식 클래스가 부모 클래스를 대신하는 것을 업캐스팅이라고 부른다. 자식 클래스가 위에 위치한 부모 클래스로 자동적으로 타입 캐스팅되는 것처럼 보이기 때문이다.


다형성

  • 다형성은 동일한 메시지를 수신했을 때 객체의 타입에 따라 다르게 응답할 수 있는 능력을 뜻한다.
    • Movie는 동일한 메시지를 전송하지만, 실제로 어떤 메서드가 실행될 것인지는 메시지를 수신하는 객체의 클래스가 무엇이냐에 따라 달라진다.
  • 다형성은 프로그램의 컴파일 시간 의존성과 실행 시간 의존성이 다를 수 있다는 사실에 기반한다.
  • 다형성은 실행될 메서드를 실행 시점에 결정하므로 지연 바인딩 또는 동적 바인딩이라고 부른다.


인터페이스와 다형성

  • 구현은 공유할 필요가 없고 순수하게 인터페이스만 공유하고 싶다면 추상 클래스가 아닌 인터페이스를 사용하면 된다.


추상화와 유연성

추상화의 힘

  • 추상화의 장점
    • 추상화의 계층만 따로 떼어 놓고 살펴보면 요구 사항의 정책을 높은 수준에서 서술할 수 있다.
    • 설계가 좀 더 유연해진다.


유연한 설계

  • 추상화는 설계가 구체적인 상황에 결합되는 것을 방지하기 때문에 유연한 설계를 만들 수 있다.


추상 클래스와 인터페이스 트레이드 오프

public abstract class DiscountPolicy {

    private List conditions;

    public DiscountPolicy(DiscountCondition... conditions) {
        this.conditions = Arrays.asList(conditions);
    }

    public Money calculateDiscountAmount(Screening screening) {
        for (DiscountCondition condition : conditions) {
            if (condition.isSatisfiedBy(screening)) {
                return getDiscountAmount(screening);
            }
        }
        return Money.ZERO;
    }

    abstract protected Money getDiscountAmount(Screening screening);
}

public class NoneDiscountPolicy extends DiscountPolicy {

    @Override
    protected Money getDiscountAmount(Screening screening) {
        return Money.ZERO;
    }
}


  • 현재 NoneDiscountPolicy는 사실 없어도 DiscountPolicy의 calculateDiscountAmount() 메서드에서 할인 조건이 없으면 0을 반환하고 있어서 문제가 없다. 그러나 사용자 입장에서 Movie의 인자로 할인 정책이 없는 None 정책을 넣어 주어야 해서 추가하였다.
  • 따라서 개념적으로 NoneDiscountPolicy 클래스가 혼란스러우므로 아래와 같이 수정하면 이해하기 좋다.


public interface DiscountPolicy {

    Money calculdateDiscountAmount(Screening screening);
}

public abstract class DefaultDiscountPolicy implements DiscountPolicy {

    private List conditions;

    public DefaultDiscountPolicy(DiscountCondition... conditions) {
        this.conditions = Arrays.asList(conditions);
    }

    public Money calculateDiscountAmount(Screening screening) {
        for (DiscountCondition condition : conditions) {
            if (condition.isSatisfiedBy(screening)) {
                return getDiscountAmount(screening);
            }
        }
        return Money.ZERO;
    }

    abstract protected Money getDiscountAmount(Screening screening);
}

public class NoneDiscountPolicy implements DiscountPolicy {

    @Override
    public Money calculateDiscountAmount(Screening screening) {
        return Money.ZERO;
    }
}

public class PercentDiscountPolicy extends DefaultDiscountPolicy {

    private double percent;

    public PercentDiscountPolicy(double percent, DiscountCondition... conditions) {
        super(conditions);
        this.percent = percent;
    }

    @Override
    protected Money getDiscountAmount(Screening screening) {
        return screening.getMovieFee().times(percent);
    }
}

public class AmountDiscountPolicy extends DefaultDiscountPolicy {

    private Money discountAmount;

    public AmountDiscountPolicy(Money discountAmount, DiscountCondition... conditions) {
        super(conditions);
        this.discountAmount = discountAmount;
    }

    @Override
    protected Money getDiscountAmount(Screening screening) {
        return discountAmount;
    }
}


  • 위와 같이 DiscountPolicy를 인터페이스로 추상화하고, 그것의 구현체인 NoneDiscountPolicy와 일반적인 할인 정책을 뜻하는 DefaultDiscountPolicy로 나누는 것이다.

Untitled

  • NoneDiscountPolicy만을 위해 인터페이스를 추가하는 것이 증가한 복잡도에 비해 효율이 떨어진다고 생각할 수도 있다.
  • 구현과 관련된 모든 것들이 트레이드 오프의 대상이 될 수 있음을 인지하고 설계해야 한다. 즉, 작성하는 모든 코드에는 합당한 이유가 있어야 한다.


코드 재사용

  • 상속은 코드를 재사용하기 위해 사용할 수 있다.
  • 하지만 코드 재사용을 위해서는 상속보다는 합성을 사용하는 것이 좋다.
  • 현재 코드에서 Movie가 DiscountPolicy의 코드를 재사용하는 방법이 바로 합성이다.
  • 만약 Movie를 상위 클래스로 두고, AmountDiscountMovie와 PercentDiscountMovie로 나눈다면 상속을 사용한 것이라 할 수 있다.


상속

  • 상속의 단점
    • 캡슐화를 위반한다.
      • 부모 클래스의 내부 구조를 잘 알고 있어야 한다.
      • 부모 클래스를 변경할 때 자식 클래스도 함께 변경될 확률이 높다.
    • 설계를 유연하지 못하게 만든다.
      • 부모 클래스와 자식 클래스의 관계를 컴파일 시점에 결정한다.
      • 실행 시점에서 객체의 종류를 변경하는 것이 불가능하다.
      • 하지만 합성은 사용하는 객체 쪽에서 chageDiscountPolicy() 와 같은 메서드를 통해 실행 시점에서 인스턴스를 교체할 수 있다.


합성

  • 인터페이스에 정의된 메시지를 통해서만 코드를 재사용하는 방법을 합성이라고 한다.
  • 캡슐화를 구현할 수 있고, 느슨한 결합을 유지할 수 있다.
  • 다형성을 위해 인터페이스를 재사용하는 경우에는 상속과 합성을 조합해서 사용해야 한다.
    • 가령, DiscountPolicy 인터페이스는 하위 구현체를 구현하기 위해 상속을 사용할 수 밖에 없다.


출처

  • 오브젝트
제이온
제이온
제이온
제이온
[오브젝트] 1장. 객체, 설계 소프트웨어 개발에서 변경 용이성과 의사소통은 중요하며, 이를 위해 객체 지향 설계를 적용해야 합니다. 객체는 자신의 데이터를 스스로 관리하는 자율적인 존재이며, 객체 간의 의존성을 적절하게 관리하는 것이 훌륭한 설계입니다.

2024년 4월 28일

[이펙티브 자바] 아이템 1. 생성자 대신 정적 팩터리 메서드를 고려하라 정적 팩터리 메서드는 생성자 대신 인스턴스를 생성하는 데 사용할 수 있는 유용한 방법입니다. 이름을 가질 수 있고, 생성자보다 더 많은 유연성을 제공하며, 플라이웨이트 패턴, 싱글톤 패턴, 서비스 제공자 프레임워크와 같은 디자인 패턴을 구현하는 데 사용할 수 있습니다.

2024년 4월 27일

[이펙티브 자바] 아이템 6. 불필요한 객체 생성을 피하라 자바에서 불필요한 객체 생성을 최소화하여 성능을 향상시키는 방법에 대해 설명합니다. 문자열, 부울, 정규 표현식, 뷰 객체, 오토 박싱 등 다양한 예시와 함께 객체 재사용의 중요성을 강조합니다. 특히 방어적 복사가 필요한 경우 객체 재사용으로 인한 문제점을 주의해야 합니다.

2024년 4월 28일

[비전공, 개발자로 살아남기] 14. 신입 개발자 자주 묻는 기술면접 내용 요약 신입 개발자 면접에서 자주 나오는 기술 질문과 답변을 정리했습니다. 메모리 영역, 자료구조, 데이터베이스, 프로그래밍 패러다임, 페이지 교체 알고리즘, 프로세스와 스레드, OSI 7 계층, TCP와 UDP 등 다양한 주제를 다룹니다.
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

2024년 4월 3일

#마케팅 - 매출공식을 알면 어려운 매출회의가 쉬워진다 매출 공식을 이용하여 DB, 객단가, 성사율을 분석하고 개선 방안을 제시하여 효과적인 매출 회의를 진행하는 방법을 알려줍니다.
30대의 존버살이를 씁니다.
30대의 존버살이를 씁니다.
30대의 존버살이를 씁니다.
30대의 존버살이를 씁니다.

2024년 1월 17일

관계형 데이터 모델링 관계형 데이터 모델링은 현실 세계의 정보를 테이블과 데이터로 나누는 과정이며, 요구 사항 분석, 개념적 데이터 모델링, 논리적 데이터 모델링, 물리적 데이터 모델링의 네 단계로 구성됩니다.
제이의 블로그
제이의 블로그
제이의 블로그
제이의 블로그

2024년 4월 8일

데이터 라벨링이란? 종류, 장점, 단점 데이터 라벨링은 컴퓨터가 데이터를 이해하고 활용할 수 있도록 데이터에 태그를 붙이는 과정입니다. 개와 고양이를 구별하는 작업을 예로 들면, 컴퓨터가 개와 고양이 사진을 구분하도록 각 사진에 "개" 또는 "고양이"라는 태그를 붙여주는 것입니다. 데이터 라벨링은 사물 인식, 텍스트 분류, 감정 분석, 음성 인식 등 다양한 분야에서 활용됩니다.
세상 모든 정보
세상 모든 정보
세상 모든 정보
세상 모든 정보

2024년 3월 29일

개념적 데이터 모델링 개념적 데이터 모델링은 정보를 엔티티로 분리하고, 엔티티 간의 관계를 ERD로 표현하는 과정입니다. 엔티티는 독립적인 데이터 저장 단위이며, 속성은 엔티티가 가진 데이터를 의미합니다. ERD에서는 식별자를 사용하여 엔티티를 고유하게 식별하며, 식별자는 기본 키, 후보 키, 대체 키, 중복 키 등으로 구분됩니다. 엔티티 간의 관계는 존재에 의한 관계와 행위에 의한 관계로 나뉘며, 카디널리티와 옵셔널리티를 통해 수적 관계와 필수/선택적 관계를 표현합니다.
제이의 블로그
제이의 블로그
제이의 블로그
제이의 블로그

2024년 4월 8일

알고리즘과의 우리의 관계 변화 최근 주목받는 ChatGPT 등 생성 AI는 인간 과학자의 역할을 수 초 만에 처리할 정도로 똑똑해지고 있습니다. 하지만 생성 AI 알고리즘은 사용자의 입력에 따라 결과물을 만들어내므로, 인간과의 관계를 새롭게 정의해야 합니다.
Byungchae Ryan Son
Byungchae Ryan Son
Byungchae Ryan Son
Byungchae Ryan Son

2024년 5월 9일