객체지향 프로그래밍과 설계(3)
업데이트:
POCU의 개체지향 프로그래밍 및 설계 강의를 듣고 정리한 내용입니다.
public
- 멤버 변수와 멤버 함수 선언 시 앞에 붙는 접근 제어자
- 외부(다른 패키지)에서 클래스 내부에 담긴 상태/동작에 접근하는 것을 허용
객체 생성과 메모리
- 자바는 기본 자료형만 stack 메모리에 생성 가능
- 참조 자료형은 heap 메모리에 저장됨(동적 할당)
// C
human_t* adam = (human_t*)malloc(sizeof(human_t));
// java
Human adam = new Human();
포인터 vs 참조형
Human adam;
- 자료형 : 사실상 포인터
- 포인터는 메모리 주소를 저장하는 변수
adam
역시 힙에 위치한 Human 객체의 주소를 담는 변수- 자바는 기본 자료형 제외하면 모두 포인터 형
- 포인터 연산은 불가능(주소값 변경 불가)
int
: 기본 자료형Integer
: 참조 자료형
C는 객체를 포인터 혹은 값으로 둘 다 전달 가능, 자바는 포인터로만 전달 가능
public void increaseAge(Human player, int age) {
player.age += age;
age = 0;
}
int age = 10;
Human adam = new Human(); // adam.age = 20
increaseAge(adam, age) // adam.age = 30, age = 10
// age는 값형, adam은 참조형
자바는 기본적으로 call by value, 값형 데이터에 대해 swap이 불가능하다.
멤버 변수의 초기값
- 자바는 비트 패턴이 0인 값으로 초기화해 줌
- int :
0
- float :
0.0
- 참조형 :
null
- int :
- 0이 아닌 값으로 초기화하고 싶으면 선언문에 대입 가능
public class Human { publicc int age = 20; }
.
연산자
- 개체의 멤버에 접근할 때 연산자를 사용
- 포인터 역참조용
*
연산자가 없음- 주소를 읽을 방법이 없음
- 따라서 언제나 그 주소에 저장된 값을 읽어 옴
garbage collection
- jvm에 내장된 가비지 컬렉터가 알아서 해 줌
- 가비지 : 더 이상 사용되지 않는 객체(힙 메모리에서)
- 더이상 해당 객체를 참조하는 변수가 없을 때, 더 이상 사용되지 않는다고 판단
- 프로그래머가 직접 메모리를 해제하지 않는다.
한계
- 가비지 컬렉터가 메모리를 수집하는 시점을 알 수 없음
- 모든 객체의 사용 여부를 판단하는 게 그리 빠른 연산이 아님
- 자원이 한정적인 시스템에는 적합하지 않음
- 자동 메모리 관리 하에서 발생하는 메모리 누수도 존재
생성자
- 생성 시 올바른 값으로 초기화하기 위함
- 개체 생성 시 자동으로 호출되는 특수한 함수
- 반환형 : 없음(
void
아님!) - 함수명 : 클래스명과 동일
public class Human {
public String name;
public int age;
public Sex sex;
public Human(String name, int age, Sex sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
}
생성자 오버로딩
코드 중복을 피하는 법
- 매개변수 수가 적은 생성자에서 매개변수 수가 많은 생성자를 호출!
this()
를 이용하면 다른 생성자를 호출할 수 있음public Human(String name, Sex sex) { this(name, sex == Sex.MALE ? 1 : 5, sex); }
기본 생성자
default constructor
- 생성자를 하나도 안 만들 경우 자동으로 생기는 생성자
- 컴파일러가 알아서 매개변수 없는 생성자를 만들어 줌
- 기본 생성자의 함수 바디는 비어 있음
생성자의 필요성
생성자는 객체를 만들어주는 계약이다
- 함수 시그니처와 마찬가지
- 함수는 블랙박스
- 호출자와 함수의 분명한 책임 분리
- 호출자는 함수 내부의 동작을 알 필요 없음
- 책임의 분리는 함수 시그니처, 선조건, 후조건 등으로 확실히 정의
외부에서 클래스 내부의 데이터를 알 필요가 없음. 이것이 데이터 추상화이고 캡슐화의 일부.
이 개념은 생성자뿐만 아닌 모든 메서드에 적용
접근 제어자
어떤 외부자들이 객체 속에 접근할 수 있는지 정의
- public : 누구나 접근 가능
- protected : 자식들만 접근 가능
- 생략 : 같은 패키지에 속한 클래스들만 접근 가능
- private : 외부 접근 금지
일반적인 접근 제어자
- 멤버 변수 :
private
또는protected
- 메서드 :
public
- 멤버 변수 접근은 메서드를 통해서만!
- 캡슐화, 추상화
private
메서드의 용도?
- 코드 중복을 막기 위함
private
과 생성자
- 생성자도 멤버 함수이므로 똑같은 규칙이 적용
new
를 못하니 적어도 생성자 하나는public
인 것이 보통
주의 : 내부란 클래스 내부를 의미한다
- 클래스 내부 != 객체 내부
- 같은 클래스에 속한 객체끼리는
private
멤버에 접근 가능
public class Human {
private int age;
...
public void punch(Human enemy) {
enemy.age -= 1; // OK
this.age += 2; // OK
}
}
패키지 접근 제어자 용도
public
대신 패키지 접근 제어자를 사용할 수 있을 때- 특정 패키지 안에서만 사용되는 클래스
public
이 아닌 내포 클래스를 최상위 클래스로 바꿀 때- 내포 클래스는 가독성 문제가 생길 수 있음
- 따라서 별도의 클래스로 분리시키는 것이 요즘 트렌드
- 이때 접근 권한을 패키지 내로 제한하는 것이
public
보다 나음
getter / setter
남이 읽을 수 있게 해주려면 getter
public class Human {
private String name;
...
public String getName() {
return this.name;
}
...
}
외부에서 변경 가능한 정보는 setter
public class Human {
private String name;
...
public void setName(String name) {
this.name = name;
}
}
장점
- 멤버 변수를 저장하지 않고 필요할 때마다 getter에서 계산 가능
- ex) 질량과 중력 멤버 변수로부터 무게를 계산
- setter에서 추가적인 로직을 실행할 수 있음
- ex) 음수의 나이가 인자로 들어올 경우 무시
- 상속을 통한 다형성 구현 가능
best practice
- 멤버 변수는
private
- 새로운 객체는 유효하도록
- 생성자를 통해 강제할 수 있음
- 매개변수가 틀릴 경우 / 바뀌는 경우 컴파일 에러 나게 유도
- getter는 자유롭게 추가
- 주의 : 특정 객체의 레퍼런스를 반환할 때는 문제될 수 있다.
- setter는 고민 후 추가
- 이상적인 객체의 상태 수정법
- 그 객체의 사용자가 어떤 동작을 지시
- 그 동작의 결과로 객체 안에 있는 특정 상태가 바뀜
- 즉, 객체 스스로 상태를 변경
- 이상적인 객체의 상태 수정법
public class Classroom {
private int[] scores;
private float mean;
...
public boolean setScore(int index, int score) {
scores[index] = score;
updateMean();
return True
}
private void updateMean() {
this.mean = 계산 결과;
}
}
정리 : 캡슐화
- 객체의 데이터(멤버 변수)와 동작(메서드)을 하나로 묶음
- 내부의 데이터를 외부로부터 보호
- 사용자가 클래스 내부를 알 필요가 없다
- 함수를 분리할 때 적용했던 원칙을 클래스에도 적용할 것!
- 중복된 코드가 있다면
private
메서드로
- 중복된 코드가 있다면
정리 : 추상화
- 추상 자료형 측 관점
- 사용자는 클래스를 자료형으로 사용할 수 있음
- 절차적 데이터 추상화 측 관점
- 데이터를 직접 조작하는 대신 메서드를 호출
어떤 구체적인 것에 직접 손대지 않겠다.
단점
- 동작 없이 데이터만 있는 클래스는 쓸데없는 코드만 늘어남
- 웹 프로그래밍에서의 DTO
- 그냥
public
데이터를 쓰기도 함
- 어떻게 추상화를 해야 하는지 객관적 기준이 없음
- 다형성, 상속, 인터페이스에서 나오는 추상화에서 특히 문제
댓글남기기