변수를 private 로 정의하는 이유?
남들이 변수에 의존하지 않게 만들고 싶어서
그러면 왜 get, set 함수를 public 으로 공개해 비공개 변수를 외부에 노출할까?
자료 추상화
public class Point{
public double x;
public double y;
}
public interface Point{
double getX();
double getY();
void setCartesian(double x, double y);
double getR();
double getTheta();
void setPolar(double r, double theta);
}
위의 Point 클래스에서는 점이 직교좌표계를 사용하는지 극좌표계를 사용하는지 알 수 없다
아래의 interface 에서는 자료구조를 명백하게 표현한다
또한, 아래의 interface 에서는 클래스 메서드가 접근 정책을 강제한다
좌표를 읽을 때에는 각 값을 개별적으로 읽어야 한다 (getX, getY)
하지만 좌표를 설정할 때는 두 값을 한꺼번에 설정해야 한다 (setCartesian(double x, double y))
위의 클래는 직교좌표계를 사용한다
개별적으로 좌표값을 설정하게 강제한다
구현을 노출한다
변수를 private 로 선언하더라도 각 값마다 get,set 함수를 제공한다면 구현을 외부로 노출하는 셈이다
public interface Vehicle{
double getFuelTankCapacityInGallons();
double getGallonOfGasoline();
}
public interface Vehicle{
double getPercentFuelRemaining();
}
아래의 인터페이스가 더 좋다
자료의 상세한 공개보다는 추상적인 개념으로 표현하는 편이 좋다
인터페이스나 조회/설정 함수만으로는 추상화가 이루어지지 않는다
아무 생각없이 get, set 메서드를 추가하는 것은 바람직하지 않다
자료/객체 비대칭
앞의 예제는 객체와 자료구조 사이에 벌어진 차이를 보여준다
객체는 추상화 뒤로 자료를 숨기고 자료를 다루는 함수만 공개한다
자료구조는 자료를 그대로 공개하며 별다른 함수는 제공하지 않는다
public class Square{
public Point topLeft;
public double side;
}
public class Rectangle{
public Point topLeft;
public double height;
public double width;
}
public class Geometry{
public double area(Object shape){
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;
}
..
}
}
위 코드에서 Geometry 클래스에 둘레 길이를 구하는 perimeter() 함수를 추가하고 싶다면?
Square, Rectangle 등의 도형 클래스는 영향을 받지 않는다
반대로 새 도형을 추가하고 싶다면 Geometry 클래스에 속한 함수를 모두 고쳐야 한다
public class Square implements Shape{
private Point topLeft;
private double side;
public double area(){
return side*side;
}
}
public class Rectangle implements Shape{
private Point topLeft;
private double height;
private double width;
public double area(){
return height*width;
}
}
...
객체지향의 개념에 부합하는 도형 클래스를 구현했다고 치자
여기서 area 는 다형메서드이다 (Geometry 클래스는 필요없다)
그러므로 새 도형을 추가해도 기존 함수에 아무런 영향을 미치지 못한다
그러나 Shape interface 에 새 함수를 추가하고 싶다면 도형 클래스를 전부 고쳐야 한다
이 두 예시가 객체와 자료구조의 반대 개념을 가장 잘 표현해준다
객체지향 코드에서 어려운 변경은 절차지향 코드에서 쉽고, 절차에서 어려우면 객체에서 쉽다
디미터 법칙
모듈은 자신이 조작하는 객체의 속사정을 몰라야 한다는 법칙
객체는 자료를 숨기고 함수를 공개 >> 객체는 조회 함수로 내부 구조를 공개하면 안된다는 의미
클래스 C
f가 생성한 객체
f 인수로 넘어온 객체
C 인스턴스 변수에 저장된 객체
이 4가지 객체의 메서드만 호출해야 한다는 뜻
구조체 구조 + 객체 구조
형태의 구조는 피하자
자료 전달 객체
자료 구조체의 전형적인 형태는 공개 변수만 있고 함수가 없는 클래스
DTO (Data Transfer Object) 라고 하기도 한다
DB와 통신하거나 소켓에서 받은 메세지 구문 분석 등 유용
좀 더 일반적인 형태는 Bean 구조
public class Address{
private String street;
private String streetExtra;
private String city;
private String state;
private String zip;
public Address(String street, String streetExtra, String city, String state, String zip){
this.street = street;
this.streetExtra = streetExtra;
this.city = city;
this.state = state;
this.zip = zip;
}
public String getSreet(){
return street;
}
...
}
Bean 은 private 변수를 get, set 함수로 조작
일종의 사이비 캡슐화
활성 레코드
DTO의 특수한 형태
보통 save, find 같은 탐색 함수도 제공
데이터베이스 테이블이나 다른 소스에서 자료를 직접 변환한 결과
활성레코드는 비즈니스 로직 메서드를 추가해 자료구조 + 객체 구조 형태를 띈다
자료구조로 취급하고 비즈니스 로직을 담으면서 내부 자료를 숨기는 객체를 따로 생성하도록 한다
'끄적 > Clean Code' 카테고리의 다른 글
Clean Code -7 단위테스트 (0) | 2023.08.14 |
---|---|
Clean Code -6 오류 처리 (0) | 2023.08.10 |
Clean Code -4 형식 맞추기 (0) | 2023.08.10 |
Clean Code -3 주석 (0) | 2023.08.10 |
Clean Code -2 함수 (0) | 2023.08.09 |