김주엽
1. 📌 핵심 개념 정리
✅ 요약하기
어째서 수많은 프로그래머가
getter/setter
를 당연하게public
으로 설정해 변수를 외부에 노출할까?
-
자료 추상화
변수를private
으로 선언하더라도 각 변수마다getter/setter
를 제공한다면 구현을 외부로 노출하는 셈이다.
추상 인터페이스를 제공해 사용자가 구현을 모른 채 자료를 조작할 수 있어야 한다.-
개선 전
public class Point { private double x; private double y; public double getX(){ return x; } public double getY(){ return y; } public void setX(double x){ this.x = x; } public void setY(double y){ this.y = y; } }
모든 멤버 변수에 대해
getter/setter
를 제공해 외부로 노출하고 있다. -
개선 후
public class Point { private double x; private double y; public double getTheta(){ Math.atan2(y, x); } }
필요한 메서드만
public
으로 설정해 멤버 변수를 외부로부터 보호하도록 개선했다.
-
-
자료/객체 비대칭
객체는 추상화 뒤로 내부는 숨긴 채 자료를 다루는 메서드만 공개한다.-
절차 지향적인 구조의 클래스
public class Square { public Point topLeft; public double side; } public class Rectangle { public Point topLeft; public double height; public double width; } public class Circle { public Point center; public double radius; public double width; } public class Geometry { public final double PI = 3.141592653585793; public double area(Object shape) throws NoSuchShapeException { if(shape instanceOf Square) { Square s = (Square)shape; return s.side * s.side; } else if(shape instanceOf Rectangle) { Rectangle r = (Rectangle)shape; return r.height * r.width; } else if(shape instanceOf Circle) { Circle c = (Circle)shape; return PI * c.radius * c.radius } } }
Geometry
클래스는 세 가지 도형을 모두 다룬다.
도형이 동작하는 방식은Geometry
클래스에서 구현하고 메서드를 추가로 구현해도 도형 클래스는 영향을 받지 않는다. 그러나 도형을 추가하고 싶다면Geometry
클래스의 메서드를 모두 고쳐야 할 수도 있다. -
객체 지향적인 구조의 클래스
public class Square implements Shape { public Point topLeft; public double side; public double area() { return side*side; } } public class Rectangle implements Shape { public Point topLeft; public double height; public double width; public double area() { return height*width; } } public class Circle implements Shape { public Point center; public double radius; public double width; public double area() { return PI*radius*radius; } }
객체 지향적인 구조의 클래스에서는
area
메서드를 도형마다 구현해 새 도형을 추가해도 기존 함수에 아무런 영향을 미치지 않는다. 그러나 새 함수를 추가하고 싶다면 모든 도형 클래스를 고쳐야 한다. -
절차 지향적인 코드 vs 객체 지향적인 코드
절차 지향적인 코드
- 기존 자료 구조를 변경하지 않고 새 메서드를 추가하기 쉽다.
- 새로운 자료 구조를 추가하기가 어렵다.
- 새로운 자료 타입이 아닌 메서드가 필요한 경우에 유리하다.
객체 지향적인 코드
- 기존 메서드를 변경하지 않고 새 클래스를 추가하기 쉽다.
- 새로운 클래스를 추가하기가 어렵다.
- 새로운 함수가 아닌 타입이 필요한 경우에 유리하다.
-
-
디미터 법칙
모듈은 자신이 조작하는 객체의 속사정을 몰라야 한다는 법칙이다.클래스
C
의 메서드f
는 다음과 같은 객체의 메서드만 호출해야 한다.- 클래스
C
:f
는 자기 자신(this)의 메서드를 호출할 수 있다. f
가 생성한 객체: 메서드f
가 만든 객체의 메서드는 호출해도 된다f
인수로 넘어온 객체:f
가 인수로 받은 객체의 메서드는 호출할 수 있다.C
인스턴스 변수에 저장된 객체: 멤버 변수로 저장된 객체는 사용 가능하다.
-
기차 충돌(train wreck)
- 여러 객체가 한 줄로 이어진 기차처럼 보이는 코드
Car car = new Car(); car.getEngine().getBattery().checkBattery(); // 기차 충돌 발생 (Car → Engine → Battery) car.getEngine().start(); // Car 내부 구조를 너무 깊이 탐색함
- 기차 충돌 코드는 다음과 같이 나누는 편이 좋다.
class Battery { public void checkBattery() { System.out.println("배터리 상태 확인: 정상"); } } class Engine { private Battery battery = new Battery(); public void start() { System.out.println("엔진 시동 걸림!"); } public void checkBatteryStatus() { // 배터리 체크는 엔진이 처리 battery.checkBattery(); } } class Car { private Engine engine = new Engine(); public void startEngine() { // 엔진을 직접 노출하지 않음 engine.start(); } public void checkBattery() { // 배터리 체크도 Car가 담당 engine.checkBatteryStatus(); } } class Driver { public static void main(String[] args) { Car car = new Car(); car.checkBattery(); // Driver는 Car에게만 요청 car.startEngine(); // Engine을 직접 알 필요 없음 } }
- 클래스
- 자료 전달 객체
Data Transfer Object
,DTO
라고 부르며 데이터베이스, 소켓에서 받은 메시지를 소통하거나 분석할 때 유용하다.public
변수만 있고 메서드가 없는 클래스의 형태를 띄고 있다.class User { public String account; public String password; public String email; public String address; }
- Bean:
private
변수를getter/setter
로 조작하는 형태@Getter class User { public String account; public String password; public String email; public String address; }
- 활성 레코드:
public
변수가 있거나private
변수에getter/setter
가 있는 자료 구조이며save
,find
와 같은 탐색 함수도 제공한다.
그러나 위와 같은 방식은 잡종 구조로 비즈니스 규칙을 담는 객체를 따로 생성하는 것을 권장한다.@Getter @Setter class User { public String account; public String password; public String email; public String address; // 데이터 저장 (DB에 저장한다고 가정) public void save() { System.out.println(account + " 유저 정보를 DB에 저장합니다."); } // 데이터 조회 (DB에서 검색한다고 가정) public static User find(String account) { System.out.println(account + " 유저 정보를 DB에서 찾습니다."); User user = new User(); user.account = account; user.password = "hashed_password"; // 실제 DB에서 불러오는 가정 user.email = account + "@example.com"; user.address = "Seoul, Korea"; return user; } }
2. 🤔 이해가 어려운 부분
🔍 질문하기
책을 읽으며 이해하기 어려웠던 개념이나 명확하지 않았던 내용을 정리합니다.
- 디미터 법칙
- 어려웠던 부분
책에 나와있는 예제를 이해하기에는 코드에 대한 정보가 조금 부족해서 이해하는데 어려웠다. - 궁금한 점
대다수의 개발자들이 기차 충돌이 발생하는 코드를 많이 작성하는데 이를 방지할 수 있는 방법이 있을까?
- 어려웠던 부분
3. 📚 참고 사항
📢 논의하기
- 관련 자료 공유
- 추가 자료
디미터의 법칙
Spring-DTO란
- 추가 자료