개체 지향 프로그래밍을 배우는데 있어 알아두면 좋은 내용들을 정리해본다.

접근제어자와 캡슐화

  • 멤버 변수 직접 접근 못하도록 해야함
  • 메서드를 통해서만 접근 가능
  • 내부에 어떤 변수가 있는지는 모르겠고, 소통은 메서드로만 해!
  • 일단 이게 기본
public class Human {
   private String name;
   private int age;

   public Human(String name, int age) {
      this.name = name;
      this.age = Math.max(age, 0);
   }
}

getter, setter

  • 누군가가 내부 정보를 궁금해하거나 변경하고 싶을 때 열어주는 메서드
  • 필요한 시점에 필요한 것만 열겠다는 발상
  • 읽게 해주려면 getter, 쓰게 해주려면 setter
  • 요즘 언어에서는 immutable property와 같은 것이 있어 방식이 바뀌고 있긴 하다.
  • get, set시 다른 작업을 해야할 수도 있기 때문에 이걸 일단 기본으로 함
    • 특수한 경우(성능 등)에 public으로 멤버 변수를 열어줌
public class Human {
   private String name;
   private int age;

   public Human(String name, int age) {
      this.name = name;
      this.age = Math.max(age, 0);
   }
}

함수를 통한 데이터 접근의 장점

  1. 멤버 변수를 저장하지 않고 필요할 때마다 getter에서 "계산" 가능
    • 메모리에 담지 않고 계산해서 던짐
  2. setter에서 추가적인 로직을 실행할 수 있음
    • 음수의 나이가 들어오는 경우 "무시"
  3. 상속을 통한 다형성 구현 가능

Best Practice

  1. 멤버 변수는 private
    • infomation hiding
  2. 새 개체는 생성함과 동시에 유효해야 한다.
    • 개체는 살아있는 동안 언제나 유효한 상태여야 이상적임
    • 실수도 방지할 수 있음
    • 생성자를 통해 강제할 수 있음
  3. getter는 자유롭게 추가
    • 알 필요 없는 정보는 안보여주는게 정석
    • 하지만 보여줘도 큰 문제는 없음
    • 그래서 자유롭게 열어둚
    • 하지만 개체의 Reference를 넘기는 경우 주의해야 함
      • C++의 경우 "읽기 전용" 레퍼런스를 반환할 수 있어 이런 문제에서 자유로움
  4. setter는 고민 후 추가
    • 이상적인 개체의 상태 수정법
      1. 개체의 사용자가 동작을 지시
      2. 동작의 결과로 개체 안에 있는 상태를 변경
        • 즉, 스스로 변경!
    • 데이터를 직접 바꾸는 녀석이기 때문에 가능한 피하자.
    • 무조건 추가하는 경우도 있긴 함.. (아무 생각 없이)
      • 만약 SDK인 경우에는 미래를 대비하여 추가하는 경우도 있음

캡슐화

개체의 데이터와 동작을 하나로 묶음 -> Class

내부의 데이터를 외부로부터 보호 -> getter, setter, 접근제어자

  • 사용자는 클래스 속을 알 필요 없음
    • 함수도 이렇게 동작
    • 추상화
  • 함수를 분리할 때 적용했던 원칙을 클래스에도 적용하면 됨

추상화

구체적인 것에 손대지 않겠다.

  • 추상 자료형(Abstract data type)쪽 관점
    • 클래스를 "사용"하는 사람의 관점
    • 캡슐화(데이터 묶음)에 좀 더 방점이 가있는 관점
    • 사용자는 클래스를 "자료형"으로 사용할 수 있음
    • 그 안에 들어간 멤버 변수가 정확히 뭔지 몰라도 됨
    • 클래스로부터 개체 생성 가능
  • 절차적 데이터 추상화(Procedural data abstraction)쪽 관점
    • 클래스를 "제작"하는 사람의 관점
    • 메서드에 좀 더 방점이 가있는 관점
    • 데이터를 직접 조작하는 대신 "메서드"를 호출
    • 동작적 개체(behavior objects) 진영이라고 하기도 함 (정식 X)

추상화의 단점

  • 동작없이 데이터만 있는 클래스는 쓸데없는 코드만 늘어남
    • DTO(Data Transfer Object)
    • 이런 경우 그냥 public을 쓰기도 함..
  • 어떻게 추상화를 해야하는지 뚜렷한 "객관적 기준"이 없음
    • 인간은 뚜렷한 실체가 없는 개념을 이해하기 어려워함
    • 이해하더라도 각자 다르게 이해함
    • 다형성, 상속, 인터페이스로 가면서 더 문제가 됨

메서드 이름 짓는 방법

분무기의 물을 뿌리는 행위을 생각해보면..

  1. 동작에 초점을 맞추기
    • 당기기: pull
    • 누르기: press
  2. 용도에 초점을 맞추기
    • 뿌리기: spray

좋은 표현력을 가지는 코드

  • 물흐르듯 읽히는 변수명
  • 단위로 한번 체크해주자(remainingWaterInML)
  • 두가지의 일을 하는 경우 And를 써서 표현해주자(sprayAndGetUsedAmountWater())
    • 물론 안 하는게 가장 좋다.
    • 만약 그래야 한다면 확실하게 표현하는게 낫다는 의미
  • 매직 넘버보다는 상수형 변수를 사용하자.

개체 지향 프로그래밍을 하며 발생하는 실수들

  1. 모든 세계를 시뮬레이션 하려는 시도를 하지 말자.
    • 필요한 것만 만들자.
    • 사용하지 않는 것을 작성하는 것은 쓸데없는 유지보수 비용의 증가를 가져온다.
  2. 코드를 여러번 고치는 건 일반적이다.
    • 적어도 2, 3번은 뒤엎어야 좋은 코드가 나온다.
    • 당연한 것이라 받아들여라.

좋은 프로그래밍 습관

  1. 사용하지 않는 코드는 삭제한다.
    • 고치는 일이 프로그래머에게는 업무와 다름없다.
    • 그 과정에서 사용하지 않는 코드는 유지보수 비용을 증가시킨다.
  2. 필요한 시점에 코드를 추가하라.
    • 미리 만들려고 하는 행동은 결국 불필요한 동작을 추가하는 것과 같다.
  3. 간단하게 만들고 살을 붙여라.
    • 처음 코드를 짤 때 가정은 거의 틀릴 가능성이 높다.
    • 그렇기 때문에 가장 간단하게 뼈대를 짜고, 이에 추후 확장이 가능토록 만드는 것이 좋다.

유연성의 두 얼굴

유연성 높은 설계가 최고는 아니다.

  • 너무 쪼갤 경우 여러 파일을 넘나 들어야 함
  • 하나의 콘텍스트로 적는 것이 보다 나은 소통을 가져올 수 있다.
  • 먼 미래 때문에 지나치게 쪼개는 것은 오버 엔지니어링
  • 프로그래머의 기본자세를 먼저 가질 것
    • 읽기 명확한 코드 생성
    • 실수를 저지르기 어려운 코드 생성
    • 문제를 해결하는 코드 생성
    • 문제가 생기면 디버깅
  • 그 이후 필요에 따라 점점 유연성을 키우는 법을 배우기

개체 지향 프로그래밍 알고 있으면 좋은 사고방식

  • 개체는 자율성을 가진다.
    • "분무기로 화분에 물을 줘": waterSpray.addWaterTo(flowerPot)
    • "분무기를 줄테니 화분아 너가 물을 줘": flowerPot.addWater(waterSpray)
    • 전자가 보다 현실세계에서 자연스러우나, 코드 세계에서는 후자가 보다 나은 방식
    • 개인적 생각: 영어적인 사고 방식으로 코드를 짜는 것이 보다 수월함
      • 주어부터 생각

Reference

profile
Goal, Plan, Execute.

0개의 댓글