객체지향의 사실과 오해

Mugeon Kim·2023년 9월 11일
0
post-thumbnail

서론


책을 읽은 이유

  • 최근 프로젝트를 하면서 과연 내가 객체지향을 생각하면서 코드를 작성을 하는가에 대한 의문점을 가지게 되었다. 그래서 많은 개발자분들이 추천하는 조영호 님의 객체지향의 사실과 오해를 읽고 리뷰를 한다.
  • 책을 8월에 구매를 하고 지금 리뷰를 작성을 합니다. 왜냐하면 처음에 책을 읽을 때 개인적으로 책을 읽는데 어렵다고 생각하여 시간이 많이 걸려서 포기와 읽기를 반복을 하다가 지금은 이해가 안되더라도 다 보는것을 목표로 잡고 읽었습니다.
  • 아직은 책의 내용을 100% 이해를 하지 못하였지만 반복하여 읽으면서 이 게시글의 내용을 지속적으로 수정하여 반복적인 학습을 하려고 합니다.

리뷰하기 이전에

  • 개발을 시작하면서 자바 orm표준 JPA, 실전주의 단위 테스트 등.. 다양한 책을 읽고 학습을 하였지만 객체지향의 사실과 오해는 기존에 구매했던 책과 다른 느낌으로 구매를 하였다.
  • 이전에 책은 어떠한 기술에 대해 더 자세하고 학습하고 알기 위해서 샀다면 객체지향의 사실과 오해는 개발자들이 말하는 객체지향이란 과연 무엇일까? 하는 궁금증을 가지고 구매를 했다.
  • 책을 다 읽고 기존에 내가 알고 있었던 객체지향과 너무 다르게 생각이 들었고 더욱 깊이있는 학습의 중요성에 대해서 알게 되었다.

본론


  • 처음 책을 리뷰를 하면서 어떻게 리뷰를 해야될지 고민을 하였다. 이 책의 모든 내용을 정리하기 보다는 내가 느끼기에 책을 읽으면서 역할, 책임, 협력, 메세지 , 추상화에 대한 내용을 강조를 한다고 생각했다. 그래서 3가지 관점에서 정리하고 마지막에 전체적인 후기를 작성하는 방식으로 리뷰를 하겠다.

  • 물론 아직 완벽하게 이해가 되지 않는 부분이 있기 때문에 정리한 내용이 틀릴 수 있다. 이 부분에 대해서는 책을 다시 읽으면서 작성을 하겠다.

객체지향?

한번 알아보자

객체지향 프로그래밍(OOP, Object-Oriented Programming)은 소프트웨어 개발 방법론 중 하나로, 현실 세계의 개념을 컴퓨터 프로그램으로 모델링하는 데 중점을 둡니다. 이 방법론은 다음과 같은 주요 개념과 원칙을 기반으로 합니다:

객체(Object)

객체는 데이터와 그 데이터를 처리하는 메서드(함수)로 이루어진 독립적인 단위입니다. 예를 들어, 자동차 소프트웨어에서 자동차 객체는 속성(색상, 속도, 모델 등)과 메서드(주행, 정지, 경적 울림 등)를 가질 수 있습니다.

클래스(Class)

클래스는 객체를 생성하기 위한 설계 도면 또는 템플릿입니다. 클래스는 객체의 속성과 메서드를 정의하고, 객체를 생성하기 위한 청사진 역할을 합니다. 예를 들어, 자동차 클래스는 모든 자동차 객체가 가져야 할 공통 특성과 동작을 정의합니다.

상속(Inheritance)

상속은 기존 클래스에서 속성과 메서드를 상속받아 새로운 클래스를 생성하는 개념입니다. 이를 통해 코드 재사용과 계층적 구조를 구현할 수 있습니다. 예를 들어, 자동차 클래스를 기반으로 스포츠카 클래스를 만들 수 있습니다.

다형성(Polymorphism)

다형성은 같은 이름의 메서드나 연산자가 다른 객체에서 다른 방식으로 동작할 수 있는 능력을 가리킵니다. 다형성을 통해 객체 간의 인터페이스를 통일시키고 유연한 코드를 작성할 수 있습니다.

캡슐화(Encapsulation)

캡슐화는 데이터와 해당 데이터를 처리하는 메서드를 하나의 단위로 묶는 것을 의미합니다. 객체 내부의 상세 구현을 감추고 외부에서는 인터페이스를 통해 접근할 수 있도록 합니다. 이를 통해 코드의 유지보수성과 보안을 향상시킬 수 있습니다.

내가 알던 캡슐화가 아니야....

  • 그동안 내가 알던 캡슐화는 private만 생각을 하였다. 하지만 조금 더 생각을 하게 되었던 시간이 되었다.
  • 캡슐화의 주된 목적은 객체 내부의 세부적인 사항(인스턴스 변수와 구현에 직접 접근;)을 감추는 것을 말한다
  1. 객체의 의존성을 느슨하게 만들고 응집도를 높일 수 있다.
    • Theater를 보면
public class Theater {
	private final TicketSeller ticketSeller;

	public void enter(Audience audience){
		// 잘못된 코드 Case#1
		// - Theater가 TicketSeller의 인스턴스 변수 ticketOffice에 직접 접근
		ticketSeller.getTicketOffice().getTicket();
		// 수정된 코드 Case#1
		// - TicketSeller 클래스에 getTicketOffice() 삭제;
		ticketSeller.sellTo(audience);

		...
}
public class TicketSeller {
    private final TicketOffice ticketOffice;

    public TicketSeller(TicketOffice ticketOffice) {
        this.ticketOffice = ticketOffice;
    }

    public void sellTo(Audience a) {
        ticketOffice.plusAmount(a.buy(ticketOffice.getTicket()));
    }
}
  1. @setter , @getter
  • 프로젝트를 진행을 하면서 lombok을 사용하면서 어노테이션을 통해 접근이 가능하다. 하지만 이것은 외부에서 접근이 가능 및 변경이 가능하다. 아래의 코드를 살펴보면 @getter와 @setter를 설정을 했다. 이것이 캡슐화? 당연히 아니다. 변수를 private로 설정이 되었지만 사실상 public이다.

  • 캡슐화를 하기 위해서 @setter 제외 및 필요한 부분에 @getter를 작성한다.

// getter, setter를 사용하면 사실상 private으로 설정을 하여도 public과 똑같다.
// 접근하기 위해서는 필요한 부분에 public 인터페이스를 통해서 접근을 해야된다.
@Getter
@Setter
public class Member {
	private String name;
    private String age;
}
  1. 정적 팩토리 메서드
  • 캡슐화와 생성자 대신 정적 팩토리를 사용을 하는게 무조건 좋은 방식은 아닙니다. 하지만 정적 팩토리 메소드를 사용하여 객체를 생성을 하면 유연성을 제공하고, 캡슐화를 더 효과적으로 표현을 할 수 있습니다.
  1. 의미 있는 이름 부여: 정적 팩토리 메소드는 이름을 자유롭게 선택할 수 있으므로 객체 생성의 의도를 더 명확하게 표현할 수 있습니다. 이로 인해 코드의 가독성이 향상됩니다.

  2. 인스턴스 캐싱: 정적 팩토리 메소드를 통해 객체를 생성하면 필요에 따라 이미 생성된 인스턴스를 재사용할 수 있습니다. 이를 통해 메모리와 성능을 최적화할 수 있습니다.

  3. 인터페이스 기반 프로그래밍: 인터페이스를 반환하는 정적 팩토리 메소드를 사용하면 클라이언트 코드가 구체 클래스 대신 인터페이스에 의존하도록 할 수 있습니다.

추가적으로 더 책을 보면서 정리를 하겠다.

역할, 책임, 협력, 메세지

객체의 행동과 상태 정의하기 : 협력, 책임, 역할

객체

  • 객체란 위에 설명한 내용과 같이 데이터와 메서드로 이루어진 독립적인 단위입니다. 이때 객체는 상태, 행동, 식별자를 지닌 실체로 상태는 특정 시점에 객체가 가진 정보의 잡합으로 객체의 특징을 표현하며 행동은 외부의 요청에 응답하기 위해 동작하고 반응하는 활동이다.

  • 자유로운 객체

    • 상태와 행위를 함께 지니며 스스로 자기 자신을 책임을 지는 객체이며 할당되는 책임이 자율적이다.
    • 책임이 자율적일 수록 추상화를 해야되고 응집도 높게. 결합도 낮게하여 캡슐화를 증진되고 인터페이스와 구현이 명확하게 분리하여 설계의 유연성과 재사용성을 증가를 시켜야 된다.

협력

  • ※ 애플리케이션의 기능을 구현하기 위해 쪼개진 기능 정의서
    • 단일 객체자 처리하기 힘든 경우 다른 객체에게 요청을 통해 다른 객체에게 도움을 요청하여 필요한 서비스를 처리한다. 즉. 협력은 요청, 응답을 통해 다른 객체와 협력을 의미를 한다.

스타벅스

  • 스터벅스 cashier라는 객체는 음류 주문을 위한 협력에 참여하고 있고 그 안에 음류 주문을 처리의 책임을 가지고 있다. 그래서 객체의 행동을 결정하는 것은 객체가 참여하고 있는 협력에 의해 결정되고 상태는 객체가 행동하는데 있어서 필요한 정보에 의해 결정한다.

책임

  • ※ 협력에 참여하기 위해 객체가 가지고 있는 기능

    • 협력에 참여하기 위해 객체가 수행하는 작은 기능으로 객체가 유지해야 하는 정보(상태)와 수행할 수 있는 행동(메서드)에 대한 추상적으로 만든 문장이다.

    • 책임에는 크게 하는 것, 아는 것의 두 가지 범주로 나눌 수 있다.

    1. 하는 것
      • 객체를 생성하거나 계산을 수행하는 등의 스스로 하는 것
      • 다른 객체에게 메시지를 보내는 것
      • 다른 객체의 활동을 제어하고 조절하는 것
    2. 아는 것
      • 행동하기 위해서 필요한 정보
      • 관련된 객체에 대해서 아는 것
      • 자신이 유도하거나 계산할 수 있는 것에 관해 아는 것

책임과 메세지
책임(Responsibility)은 객체가 수행하는 일 또는 가지고 있는 역할을 나타내며, 이것은 주로 클래스의 메서드에 해당합니다.
메시지(Message)는 객체 간 상호 작용을 이끄는 수단으로, 객체는 메시지를 통해 다른 객체에게 어떤 작업을 수행하도록 요청합니다. 책임은 객체의 동작과 역할을 정의하고, 메시지는 객체 간의 협력을 촉발하는 통신 수단입니다.

// CoffeeShop 클래스
public class CoffeeShop {
    private String name;
    private double revenue;

    // 커피 주문을 처리하는 메서드 -> 책임의 아는 것
    public void takeOrder(Customer customer, String coffeeName) {
        // 커피를 만들고 가격을 계산하는 로직을 구현
        double price = calculatePrice(coffeeName);
        
        -> 여기서 cutomer에게 메세지를 보낸다.
        customer.payForCoffee(price);
        
        revenue += price;
        System.out.println(name + "에서 " + customer.getName() + "이(가) " + coffeeName + " 커피를 주문했습니다.");
    }

    // 커피 가격 계산을 수행하는 메서드
    private double calculatePrice(String coffeeName) {...}
}

// Customer 클래스
public class Customer {
    private String name;
    private double wallet;


    // 커피 가격을 지불하는 메서드 -> 책임의 하는 것
    public void payForCoffee(double price) {
        if (wallet >= price) {
            wallet -= price;
            System.out.println(name + "이(가) " + price + "달러를 지불했습니다.");
        } else {
            System.out.println(name + "의 지갑에 돈이 부족합니다.");
        }
    }
}

역할

  • ※ 동일한 책임을 수행하는 객체
  • 책에서 왕, 토끼, 엘리스를 예시로 설명을 한다. 이때 여러 개의 협력을 보면서 역할을 설명하는데 역할은 협력 내에서 다른 객체로 대체할 수 있음을 나타내는 일종의 표식이다. 라고 작성이 되어있다.
  • 하나의 협럭에 동일한 책임을 수행하는 여러 개의 객체가 있는 경우 우리는 개별적으로 협력을 나누지 않는다. (중복) 우리는 이를 추상화를 한다. 아직 이 부분에 대해서 더욱 학습이 필요한거 같다.

결론


  • 객체지향에 대해서 학습이 필요하다고 생각해서 객체지향의 오해와 진실을 구매를 하고 읽어보니 지금까지 내가 알고 있었던 내용과 너무 깊이가 달라서 추가적인 학습이 필요하겠다고 생각합니다.
  • 일단 목표는 객체지향의 사실과 오해를 몇번 더 읽고 클린코드 & 조영호님의 오브젝트를 한번 서서 읽고 DDD에 대해서 학습을 하겠습니다.
  • 이상 1회독 느낀 점 입니다.

참고


https://brawny-yellowhorn-474.notion.site/java-OOP-477254766b5440059732a48d0fba2780

https://bperhaps.tistory.com/entry/%EC%BA%A1%EC%8A%90%ED%99%94%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-%EC%96%B4%EB%96%A4-%EC%9D%B4%EC%A0%90%EC%9D%B4-%EC%9E%88%EB%8A%94%EA%B0%80

profile
빠르게 실패하고 자세하게 학습하기

0개의 댓글