1. 접근 제어자란
클래스·필드·메서드·생성자에 대해 “어디까지 접근을 허용할 것인지”를 정하는 키워드
캡슐화를 통해 불필요한 의존을 막고, 안정성과 유지보수성을 높이기 위한 핵심 장치
1. 접근 제어자의 종류 (4가지)
| public | 어디서든 접근 가능 |
| protected | 같은 패키지 + 다른 패키지의 자식 클래스 |
| (default) | 같은 패키지 |
| private | 같은 클래스 내부 |
default는 키워드가 없으며, 흔히 package-private라고 불린다.
2. 접근 범위 비교 표
| 같은 클래스 | O | O | O | O |
| 같은 패키지 | O | O | O | X |
| 다른 패키지 | O | △(상속) | X | X |
3. 각각 언제 사용하는가
1) public
- 외부에 공개해야 하는 API
- 컨트롤러, 서비스 인터페이스, DTO의 getter 등
2) protected
- 상속 관계에서만 허용하고 싶을 때
- 프레임워크 확장 포인트에서 주로 사용
실무에서는 의도가 명확하지 않으면 오히려 혼란을 주므로 남용 금지
3) default (package-private)
- 같은 패키지 내부에서만 협력하는 클래스들
- 도메인 로직, 내부 구현체
4) private
- 클래스 내부 구현을 완전히 숨김
- 필드, 내부 로직 메서드
접근 제어의 기본은 private → 필요할 때만 개방
4. 접근 제어자가 중요한 이유
1) 캡슐화
- 내부 구현 변경 시 외부 코드 영향 최소화
2) 안정성
- 잘못된 접근으로 인한 버그 방지
3) 유지보수성
- 변경 범위가 명확해짐
4) 설계 의도 표현
- “이건 써도 되고, 이건 쓰면 안 된다”를 코드로 명시
5. 실무 기준 권장 원칙
- 필드 → 무조건 private
- 메서드 → 필요한 만큼만 공개
- 클래스 → 외부 공개 아니면 default
- protected → 상속 설계가 확실할 때만
접근 범위는 좁을수록 좋다
공개는 되돌리기 어렵다.
2. 접근제어자의 사용이 불가능하다면.
결론부터 말하자면
자바로 대규모·장기 운영 서비스는 사실상 불가능
1. 캡슐화 붕괴 → 코드가 즉시 망가짐
모든 필드·메서드가 외부에 노출된다고 가정하면:
member.age = -100;
member.status = null;
member.password = "1234";
- 도메인 무결성 보장 불가
- 검증 로직이 의미 없어짐
- 객체가 “객체”가 아니라 그냥 데이터 덩어리가 된다.
-> 객체지향 설계 자체가 성립하지 않음
2. 변경 불가능 → 유지보수 비용 폭증
접근 제어자가 없으면:
- 내부 구현 = 외부 계약(API)
public int calculatePrice() { ... }
이 메서드를:
- 이름 변경 ❌
- 파라미터 변경 ❌
- 내부 로직 교체 ❌
-> 하나 고치면 연쇄 장애 발생
3. 팀 개발에서 즉시 파탄
실무는 여러 사람이 동시에 개발.
접근 제어자가 없다면:
- 누가 어디까지 써도 되는지 기준이 없음
- 다른 팀이 내부 메서드를 마음대로 사용
- “이거 쓰면 안 되는 거였어요?” 상황 반복
-> 코드 리뷰, 책임 분리, 협업 모두 붕괴
4. 보안 문제 (실무에선 치명적)
public String password;
public boolean isAdmin;
- 인증·인가 우회 가능
- 내부 상태 조작 가능
- 실제 사고로 이어질 수 있음
-> 접근 제어자는 1차 보안 장치
5. 프레임워크 사용 불가 수준
Spring / JPA에서 즉시 문제
- JPA 엔티티 필드 → private 필수
- 프록시, Lazy Loading → 접근 제어 전제
- 서비스 계층 → 외부 API / 내부 로직 분리
접근 제어자가 없다면:
- 프록시 패턴 불가능
- AOP 적용 불가
- 레이어드 아키텍처 붕괴
6. 테스트 코드도 망가진다
- 테스트는 공개 API 기준으로 작성해야 의미 있음
- 접근 제어자가 없으면 내부 구현에 의존한 테스트 작성됨
-> 리팩터링 = 테스트 전면 수정
7. 객체지향 5대 원칙 전부 붕괴
| SRP | 책임 경계 붕괴 |
| OCP | 변경이 곧 외부 영향 |
| LSP | 상속 안정성 붕괴 |
| ISP | 불필요한 의존 증가 |
| DIP | 추상화 의미 상실 |
즉 접근 제어자를 사용하지 못한다는 것은
객체의 경계를 정의하지 못한다는 의미이며,
이는 유지보수·보안·협업이 전부 무너진다는 뜻.
Q1. 왜 getter/setter를 쓰나요?
A1. 필드를 private으로 숨기고, 접근 경로를 통제하기 위해서
Q2. 생성자도 접근 제어자를 가질 수 있나요?
A2. 가능하며, 싱글톤·팩토리 패턴에서 자주 사용
Q3. 인터페이스 메서드는 왜 접근 제어자를 안 쓰나요?
A3. 기본이 public abstract이기 때문
'Daily Dev Q&A' 카테고리의 다른 글
| 스프링 프레임 워크 (0) | 2025.12.22 |
|---|---|
| 트랜잭션 (0) | 2025.12.21 |
| 람다표현식 (0) | 2025.12.19 |
| Collections Framework (0) | 2025.12.09 |
| SOLID원칙 (0) | 2025.12.07 |