1장 절차지향과 비교하기

절차지향과 객체지향의 비교

  • 자바를 사용한다고 모두 객체지향적으로 코드를 작성한 것은 아니다.
  • 자바를 사용하면서도 충분히 절차지향적으로 코드를 작성할 수 있다.
  • 절차지향적인 코드가 객체지향적인 코드가 되려면 객체가 단순 전달하는게 아니라 무엇가를 하도록합니다.
  • 예를들어, 객체에 어떤 메세지를 전달할 수 있게 됐거나, 객체가 어떤 책임을 지거나, 객체가 어떤 책임을 스스로 처리하는 방법을 알고 있는 등이 있을 수 있습니다.
  • 가독성 측면에서 사람과 프로젝트 규모 등 다양한 요소에 따라 객체지향보다 절차지향이 더 가독성이 좋다고 느낄 수 있다.
  • 객체지향은 가독성의 측면보다는 책임에 집중하기 때문입니다. 왜냐하면 어떤 객체에 이런 요청을 했을 때, 동작은 알 수 없지만 약속한 규격의 데이터를 반환 할 것이라고 믿기 때문입니다.
  • 이러한 규칙이 바로 객체지향을 설명 할 수 있습니다. 내부에 동작을 정확히 모르더라도(캡슐화, 정보 은닉) 어떠한 규격으로 데이터를 반환할 것이라는 약속(추상화)

책임과 역할

  • 절차지향도 책임을 분할할 수 있습니다. 절차지향은 함수 단위로 책임을 가질 수 있습니다.
  • 절차지향이 객체지향이 될 수 없는 이유는 객체지향에서는 책임을 객체나 함수가 아닌 역할에 책임을 할당합니다. 그리고 이것은 절차지향 언어들에서 지원하지 못하는 기능입니다.
  • 여기서 역할을 대표하는게 객체지향에서 흔히 말하는 추상화의 원리를 이용해 다형성을 지원하도록하는 것을 의미합니다.
  • 예를들어 쇼핑몰 서비스에서 가격이라는건 중요한 요소입니다. 여기서 ‘지불 해야할 가격을 구하기’을 역할로 정하고 다형성을 이용한다면 개별 상품이든, 상품들이 담긴 장바구니에서도 역할을 기반으로 동작하도록 설정할 수 있습니다.
  • 역할에 책임을 할당하는 것은 객체지향에서 아주 중요합니다. 왜냐하면 실제 객체가 무엇인지 중요하지않고 내가 원하는 역할을 할 수 있는 객체라면 모두 사용할 수 있기 때문에 확장에 유연해집니다. 새로운 요구사항이 발생할 경우 그 역할을 할 수 있는 새로운 구현체를 만들면 됩니다.
  • 객체지향의 본질은 언어나 문법이 중요하지않고 역할, 책임, 협력이라고 할 수 있습니다.
  • 많은 책들에서 객체지향은 실세계를 반영한다고 이야기합니다. 하지만 객체지향이란 자아를 가진 객체들이 서로 협력하는 방식으로 개발되는 것에 가깝습니다.
  • 아마 클린아키텍처를 공부해보셨다면 위 내용들이 결국 ‘구체적인 것이 아닌 추상적인 것에 의존하라’ 또는 ‘저수준의 구현보다는 고수준의 정책을 의존하라’를 의미하고 있습니다.

TDA

  • 절차지향적인 사고에서 벗어나 객체지향적인 사고를 하기 위한 방법으로 TDA 원칙이 있다.
  • Tell, Don’t Ask, 묻지말고 시키도록 한다는 의미입니다. 이 원칙은 객체를 능동적으로 동작하도록 하는 방법입니다.
// Bad-Case
public class Shop {

  public void sell(Account account, Product product) {
    long price = product.getPrice();
    long milleage = account.getMoney();
    if (milleage >= price) {
      account.setMoney(milleage - price);
      System.out.println(product.getName() + "를 구매했습니다.");
    } else {
      System.out.println("잔액이 부족합니다.");
    }
  }
}

@Setter
@Getter
class Account {
  private long money;
}

@Setter
@Getter
class Product {
  private String name;
  private long price;
}
// Good-Case
public class Shop {

  public void sell(Account account, Product product) {
    if (ammount.canAfford(product.getPrice()) {
      account.withdraw(product.getPrice());
      System.out.println(product.getName() + "를 구매했습니다.");
    } else {
      System.out.println("잔액이 부족합니다.");
    }
  }
}

class Account {
  private long money;
  
  public boolean canAfford(long amount) {
    return money >= amount;
  }
  
  public void withdraw(long ammount) {
    money -= amount;
  }
}

class Product {
  private String name;
  private long price;
  
  public String getName() {
    return name;
  }
  
  public long getPrice() {
    return price;
  }
}
  • 위 예제의 Good-Case를 보면 사용자의 잔액을 물어보도록 하는게 아니라(수동적) 사용자가 해당 물건을 구매할 수 있는지 묻는(능동적)으로 동작하고 있습니다.
  • 또 TDA는 무분별하게 사용되는 Getter, Setter를 지양하자는 의미도 가지고 있습니다. 실제로 Getter와 Setter는 개발자의 객체지향적 사고를 방해하는 요소가 될 수 있습니다. Getter와 Setter가 무분별하게 사용되는 객체는 Manager나 Util을 이용한 코드를 작성하여 많은 클래스가 생겨납니다.
  • TDA는 단순하면서도 객체 지향을 관통하는 원칙입니다. 또한 객체는 마치 자아를 가진 것처럼 움직여야하고 객체는 단순히 데이터를 나르기 위한 수동적인 존재가 아닙니다.
  • 객체에게 모든 일을 시킬수는 없습니다. Getter는 상황에 따라서 반드시 필요한 메서드이며 객체에게 일을 최대한 시키려고해도 어딘가에선 협력을 위해서 게터를 사용해야하는 상황이 생길 수 있습니다.

' > 자바 스프링 개발자를 위한 실용주의 프로그래밍' 카테고리의 다른 글

Preview  (1) 2024.09.19
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유