클린코드 chap 6. 객체와 자료구조로 데이터 표현하기

최준영·2021년 10월 6일
0

클린한 코드

목록 보기
7/16
post-thumbnail

1. 자료구조 vs 객체


자료구조(data structure)

  • 데이터 그 자체
  • 자료를 공개한다.
  • 변수 사이에 조회 함수와 설정 함수로 변수를 다룬다고 객체가 되지 않는다.(getter, setter)

객체(Object)

  • 비즈니스 로직과 관련
  • 지료를 숨기고, 추상화 한다.
  • 자료를 다루는 함수만 공개한다.
  • 추상 인터페이스를 제공해 사용자가 구현을 모른 채 자료의 핵심을 조작할 수 있다.

예제

예제 1. 자료구조

  • 단순히 getter, setter가 있다고 객체가 되지 않는다.
public interface Vehicle {
  double getfuelTankCapacityInGallons(); // 연료탱트 용량(갤런 단위)
  double getGallonsOfGasoline(); // 가솔린 (갤런 단위)
}

public class Car implements Vehicle {
  double fuelTankCapacityInGallons;
  double gallonsOfGasoline;
  
  public double getFuealTankCapacityInGallons() {
    return this.fualTankCapacityInGallons;
  }
  
  public double getGallonsOfGasoline() {
    return this.gallonsOfGasoline;
  }
}

예제 2. 객체

  • 자신이 가진 값을 그대로 주는 것이 아닌, 연료를 퍼센트로 변환하는 로직이 들어있다.
public interface Vehicle {
  double getPercentFuelRemain();
}

public class Car implements Vehicle {
  double fuelTankCapacityInGallons;
  double gallonsOfGasoline;
  
  public Car(double fuelTankCapacityInGallons, double gallonsOfGasoline) {
    if (fuelTankcapacityInGalons <= 0) {
      throw new IllegalArgumentException("fuelTankCapacityInGallons은 0보다 커야한다.");
      this.fuelTankCapacityInGallons = fuelTankCapacityInGallons;
      this.gallonsOfGasoline = gallonsOfGasoline;
    }
    
    public double getPercentFuelRemain() {
      return this.gallonsOfGasoline / this.fuelTankCapacityInGallons * 100;
    }
  }
}

절차 지향과 객체 지향

  • 상황에 맞는 선택을 하면 된다.

절차 지향

  • 자료구조를 사용하는 절차적인 코드는 기본 자료 구조를 변경하지 않으면서 새 함수를 추가하기 쉽다.
  • 절차적인 코드는 새로운 자료구조를 추가하기 어렵다. 그러려면 모든 함수를 고쳐야 한다.

객체 지향

  • 객체 지향 코드는 기존 함수를 변경하지 않으면서 새 클래스를 추가하기 쉽다.
  • 객체 지향 코드는 새로운 함수를 추가하기 어렵다. 그러려면 모든 클래스를 고쳐야 한다.

2. 객체 - 디미터 법칙


  • 클래스 C의 메서드 f는 다음과 같은 객체의 메서드만 호출해야 한다.
    • 클래스 C
    • 자신이 생성한 객체
    • 자신의 인수로 넘어온 객체
    • C 인스턴스 변수에 저장된 객체
  • 휴리스틱 : 경험에 기반하여 문제를 해결하기 위해 발견한 방법. 의사 결정을 단순화하기 위한 법칙들

예제 3. 객체로서 옳지 않는 방법

// 객체 - 기차 충돌. 디미터의 법칙을 위배한다.
final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();

// 자료구조 - OK
final String outputDir = ctxt.options.scratchDir.absolutePath;

// 객체에 대한 해결책이 아니다. getter를 통했을 뿐, 값을 가져오는 것은 자료구조이다.
ctxt.getAbsolutePathDirectoryOption();
ctxt.getScratchDirectoryOption().getAbsolutePath();

예제 4. 객체로서 옳은 방법

BufferdOutputStream bos = ctxt.createScratchFileStream(classFileName);
  • 이전 예제는 단순히 값을 가져오고 있기 때문에 자료구조이다.
  • 객체로 사용하려면 그 값을 가지고 기능을 제공하는데에 초점을 맞춘다.
  • 절대경로를 ctxc를 통해 주기보다는, ctxc에서 절대경로 값을 사용하여 생성한 객체를 반환하는 기능을 부여했다.

3. DTO


  • Data Transfer Object = 자료구조
  • 다른 계층간 데이터를 교환할 때 사용한다.
  • 로직 없이 필드만 갖는다.
  • 일반적으로 클래스 명이 Dto(or DTO)로 끝난다.
  • getter/setter를 갖기도 한다. - 자바
    • 필드를 public으로 오픈하기도 한다. - 코틀린

Beans

  • Java Beans: 데이터 표현이 목적인 자바 객체
  • 멤버 변수는 private 속성이다.
  • getter와 setter를 가진다.

4. Active Record


  • Database row를 객체에 맵핑하는 패턴
  • 비즈니스 로직 메서드를 추가해 객체로 취급하는 건 바람직하지 않다.
    • 비즈니스 로직을 담으면서 내부 자료를 숨기는 객체를 따로 생성한다.
    • 하지만, 객체가 많아지면 복잡하고 가까운 곳에 관련 로직이 있는 것이 좋으므로 현업에서는 Entity에 간단한 메서드를 추가해 사용한다.

Active Record vs Data Mapper

Active Record

  • 객체가 row를 담을 뿐 아니라 database에 대한 접근을 포함한다.
  • Person의 속성을 담을 뿐 아니라, 생성 수정도 객체 안에서 수행할 수 있다.
  • 사례 - Ruby on rails

Data Mapper

  • row를 담는 객체와 databse에 접근할 수 있는 객체가 분리되어 있다.
  • Person은 값만 담고 있고, 생성, 수정 등 액션은 Person Mapper에서 담당한다.
  • 사례 - Hibernate
profile
do for me

0개의 댓글