🥔💬 1편에 이어 마저 해보겠습니다!
public 필드를 private로 변경하고 접근할 수 있는 방법 제공
구성 요소의 데이터와 동작이 밀접하게 연관되어 있고 코드에서 같은 위치에 있다면 이 구성 요소를 유지 관리하고 개발하기 쉬움
객체 필드에 대한 접근과 같은 복잡한 작업 수행 가능
메소드가 컬렉션을 반환한다면 getter의 반환 값을 읽기 전용으로 만들고 해당 컬렉션을 추가/제거하는 메소드 제공
컬렉션 필드는 클래스 내부에서 캡슐화됨
getter가 호출되면 컬렉션의 복사본을 반환하여 컬렉션을 포함하는 클래스에 대한 지식 없이 컬렉션 요소를 실수로 변경하거나 덮어쓰는 것을 방지
컬렉션 요소에 배열과 같은 primitive type이 포함되어 있다면 컬렉션일 때의 작업보다 편리한 메소드를 생성
컬렉션의 원하지 않는 표준 메소드에 대한 접근을 제한할 수 있음
특별한 의미를 가지는 숫자 값을 의미를 나타낼 수 있는 이름의 상수로 표현
매직 넘버라고 해서 특별한 거인줄...
상징적인 상수는 별도의 주석없이 의미를 전달 가능
다른 목적으로 다른 곳에서 사용된 동일한 숫자를 실수로 변경할 위험이 감소되고 상수 값 변경이 쉬워짐
코드에서 숫자나 문자열의 중복 감소
클래스의 행동에 영향을 받지 않는 유형 코드가 클래스 내부에 있다면 해당 코드들을 새로운 클래스로 변경
O형은 0, A형은 1, B형은 2, AB형은 3의 값을 가지고
bloodgroup은 이 사람이 어떤 혈액형을 가지는 지를 나타낸다면
bloodgroup에 0~3이 아닌 숫자를 넣어도 문제가 없으니
BloodGroup이라는 클래스에서 혈액형 코드를 관리
<변경 전>
public class ReplaceTypeCodeWithClass_before {
static public class Person {
public static final int O = 0;
public static final int A = 1;
public static final int B = 2;
public static final int AB = 3;
private int bloodGroup;
public Person (int bloodGroup) {
this.bloodGroup = bloodGroup;
}
public void setBloodGroup(int arg) {
bloodGroup = arg;
}
public int getBloodGroup() {
return bloodGroup;
}
}
public static void main(String[] args) {
Person thePerson = new Person(Person.A);
System.out.println("Blood group : " + thePerson.getBloodGroup());
thePerson.setBloodGroup(Person.AB);
System.out.println("Blood group : " + thePerson.getBloodGroup());
}
}
이러면 Person.O/A/B/AB 대신 5, 6을 넣어도 문제 없음
<변경 후>
public class ReplaceTypeCodeWithClass_before {
static public class Person {
private BloodGroup _bloodGroup;
public int getBloodGroupCode(){
return _bloodGroup.getCode();
}
public BloodGroup getBloodGroup(){
return _bloodGroup;
}
public Person(BloodGroup bloodGroup){
_bloodGroup = bloodGroup;
}
public void setBloodGroup(BloodGroup arg){
_bloodGroup = arg;
}
}
public static class BloodGroup{
public static final BloodGroup O = new BloodGroup(0);
public static final BloodGroup A = new BloodGroup(1);
public static final BloodGroup B = new BloodGroup(2);
public static final BloodGroup AB = new BloodGroup(3);
private static final BloodGroup[] _values = {O, A, B, AB};
private final int _code;
private BloodGroup(int code){
_code = code;
}
public int getCode(){
return _code;
}
public static BloodGroup code(int arg){
return _values[arg];
}
}
public static void main(String[] args) {
Person thePerson = new Person(BloodGroup.A);
System.out.println("Blood group : " + thePerson.getBloodGroupCode());
thePerson.setBloodGroup(BloodGroup.AB);
System.out.println("Blood group : " + thePerson.getBloodGroupCode());
}
}
객체 지향 프로그램의 취지에 맞는 방식
프로그래밍 언어 수준에서 메소드 및 필드에 전달된 값에 대한 타입 힌트 제공
ex) 컴파일러는 이전에 값이 전달될 때 타입 코드와 임의의 숫자/문자열 사이의 차이를 몰랐지만 이제는 표시된 유형 클래스에 맞지 않는 데이터가 전달되면 IDE 내부 오류 발생
클래스의 행동에 영향은 받지만 변경할 수 없는 타입 코드가 있다면 서브클래스로 변경
단일 책임 원칙 준수를 향상시키고 프로그램을 읽기 쉽게 함
코딩된 타입에 대한 새 값을 추가해야 할 때 기존 코드를 건드리지 않고 새 하위 클래스를 추가하면 됨 (개방 폐쇄 원칙)
미리 정의한 타입 외 다른 값 사용 불가능
클래스의 행동에 영향을 받는 타입 코드가 있다면 해당 타입 코드를 상태 객체로 변경
객체의 수명동안 값이 변경되는 상황을 방지할 수 있음
값의 교체는 원래 클래스가 참조하는 상태 객체를 통해 이뤄짐
코딩된 타입에 대한 새 값을 추가해야 할 때 기존 코드를 건드리지 않고 새 하위 클래스를 추가하면 됨 (개방 폐쇄 원칙)
상수 데이터를 반환하는 메소드만 있는 하위 클래스가 있다면 메소드를 모두 상위 클래스로 옮기고 하위 클래스는 제거
📑 참고 자료