static, 싱글턴, 내포 클래스
static
모든 것이 개체 속에 있는 불편함
- 이런 단순한 계산도 개체를 만들어서 해야 하나?
- 개체 단위기 아니라 클래스 단위에서 뭔가를 하고 싶을 때는?
정적 멤버 함수 예
// Math.java
public class Math{
public static int abs(int n){
return n < 0 ? -n : n;
}
public static int min(int a, int b){
return a < b ? a : b;
}
public static int max(int a, int b){
return a > b ? a : b;
}
}
// 메인 함수
int absValue = Math.abs(-2);
int minValue = Math.min(100, -200);
정적 멤버 함수
- 멤버 함수 시스내처에 static만 붙여주면 됨
- 이 멤버 함수의 소유주는 인스턴스가 아니라 클래스
- 정적 멤버 함수를 호출할 때는?
- <개체명>.<함수명>() - 세모
- <클래스면>.<함수명>() - O
- new를 이용해서 개체를 만들지 않아도 됨!
클래스 다이어그램과 정적 멤버 함수
- 정적 멤버 함수 아래에 밑줄을 그음
Math 개체 생성 후, 함수 호출하기 예
// 메인 함수
Math math = new Math();
int absValue = math.abs(-2);
int minValue = math.min(100, -200);
- 개체.메서드()는 클래스에 속한 메서드를 호출
- 생성된 개체 수에 상관 없이 클래스는 단 하나만 존재
- 즉, 어떤 개체라도 호출해야 하는 메서드를 특정할 수 있음
Math 개체 생성 금지 예
// Math.java
public class Math{
private Math(){}
public static int abs(int n){
return n < 0 ? -n : n;
}
public static int min(int a, int b){
return a < b ? a : b;
}
public static int max(int a, int b){
return a > b ? a : b;
}
}
// 메인 함수
int absValue1 = Math.abs(-2); // OK
Math math = new Math(); // compile error
int absValue2 = math.abs(-2);
- private 생성자는 꼼수에 가깝다
- C#에는 static class가 있음
정적 멤버 변수
public class ColaCan {
private int remainingMl;
private static int numCreated;
public ColaCan(int initialMl){
this.remainingMl = initialMl;
++numCreated;
// ++this.numCreated; // OK
// ++ColaCan.numCreated; // OK
}
public void pour(int ml){
// ml만큼 비우는 코ㅗ드
}
}
- static 메서드와 마찬가지로 밑줄을 그음
정적 멤버 변수에 접근하는 정적 메서드
public class ColaCan {
private static int numCreated;
//...
public static void printStats() {
System.out.println("# Cola Produced: " + numCreated);
}
}
// 메인 함수
ColaCan.printStats();
ColaCan cola = new ColaCan(355);
ColaCan.printStats();
cola new ColaCan(500);
cola.printStats();
정적 메서드에서 비정적 메서드 접근하기
- 불가능
- 클래스에 속한 메서드가 개체에 속한 멤버(함수/변수)에 접근 불가
- 정적 메서드에서는 정적 멤버 변수/함수만 접근 가능
static 정리
- static 멤버 변수 및 멤버 함수는 클래스에 속함(딱 하나만 존재)
- static 아닌 것은 개체에 속함(따라서 개체 수만큼 존재)
- 비정적 -> 정적: 접근 가능
- 정적 -> 비정적: 접근 불가능
static이 C의 전역 변수/함수보다 좋은 점
- 접근 범위 제어 가능
- 클래스 내부에 위치하기 때문에 이름 충돌이 적음
static을 비판하는 사람들
- '모든 것은 개체여야 한다'라고 주장하는 소수설 지지자
- 자칭 순수 OO 주창자들
- static은 '순수한 OO가 아니다'
- 다른 언어 진영의 사람들
- OOP가 절차적 프로그래밍을 완전히 대체할 것이라는 도발 때문
- 이 도발의 역효과로 오히려 다른 언어 진영에서 핀잔을 주곤 했음
static 비판에 대한 결론
- static을 쓰는 게 OO의 개념과 먼 것은 사실
- 그러나 OO의 개념과 멀다고 그게 잘못된 방법은 아님
- 훌륭한 프로그래머의 자세
- OO와 절차적 개념을 언제, 어디서 각각 써야 하는지 안다!
- Java가 static을 넣은 건 잘한 일!
디자인 패턴과 싱글턴
- 프로그래밍에서 주로 베스트 프랙티스라고 불려 온 것을 좀 더 범용적, 추상적 OO 설계로 발전시킨 게 디자인 패턴
디자인 패턴
- 소프트웨어 설계에서 흔히 겪는 문제에 대한 해결책
- 범용적, 반복적
- 완성된 설계가 아님
- 곧바로 코드로 바뀌지 않음
- 어떤 문제를 다양한 환경에서 해결하는 법을 설명한 가이드로 생각하길
- 흔히 GoF라고 불리는 저자들의 1994년 책에서 등장
디자인 패턴의 장점(이라 주장한 것)
- 이미 테스트를 마친 검증된 개발 방법을 사용해 개발 속도를 향상
- 공통 용어 정립을 통한 개발자들 간의 빠른 의사소통 촉진
디자인 패턴의 단점(으로 비판 받은 것)
- 고치려는 대상이 잘못됨
- GoF 책의 패턴 중 과반수는 C++ 언어의 미지원 기능에 대한 미봉책
- 곧바로 적용할 수 없는 참고 가이드를 '패턴'이라 부를 수 없음
- 잘못 적용하는 경우가 빈번
- 오히려 프로그램을 더 복잡하게 만듦
- 비효율적인 해법이 되는 경우가 많음
- 디자인 패턴은 범용적, 추상적
- 코드 중복이 많아지고 성능이 떨어질 수 있음
- 다른 추상화 기법과 크게 다르지 않음
- 이미 프로그래밍 분야에 존재하던 현상에 왜 굳이 건축 용어를 사용?
세상이 바뀌었다
- 자체 개발팀의 증가
- 제품에 대한 사람들의 인식 혹은 비즈니스 모델 변화
- 버전 별 배포, 서포트 기간
- 배포 방식의 변화
- 웹 서비스(간단한 함수 단위의 약속으로 회귀)
- 인터넷을 통한 패키지 관리 시스템
- Git 등의 버전 관리 시스템
- 언제든 예전 코드로 돌아갈 수 있음
- 인터넷에서 더 훌륭한 해답을 찾을 수 있음
싱글턴 패턴
- 어떤 클래스에서 만들 수 있는 인스턴스 수를 하날 제한하는 패턴
- 다음과 같은 조건을 충족하는 개체에 적합
- 프로그램 실행 중에 최대 하나만 있어야 함
- 예: 프로그램 설정, 파일 시스템 등
- 이 개체에 전역적으로 접근이 가능해야 함
- 프로그램 실행 중에 최대 하나만 있어야 함
- 딱 하나만 존재해야 하니 이름도 싱글턴
싱글턴 패턴의 비공식적 정의
- 일부 사람들이 static을 싫어하는 이유
- 전역 변수 같아 보임
- 개체가 아님
- 이러한 이유로 static 사용이 OO가 아니라고 주장
- 싱글턴은 이러한 비판을 해결하는 패턴
- 그러면서도 OO에서 전역 변수 및 전역 함수를 만드는 법
싱글턴 패턴의 클래스 다이어그램
- private 생성자
- static 메서드를 통해서만 개체를 얻어올 수 잇음
- 아직 개체가 없는 경우
- 개체를 생성 후 static 변수에 저장
- static 변수에 저장된 개체를 반환
- 이미 개체가 있는 경우
- static 변수에 저장되어 있는 개체를 반환
static으로는 못하는 일
- 다형성을 사용할 수 없다
- 시그내처를 그대로 둔 채 멀티턴 패턴으로 바꿀 수 없다
- 개체의 생성 시점을 제어할 수 없다
- Java의 static은 프로그램 실행 시에 초기화 됨
- 단, 싱글턴을 사용해도 제어에 어려움이 있음
싱글턴 개체의 생성 시기
- 처음으로 getInstance() 메서드가 호출될 때
- 하지만 보통 다양한 개체에서 getInstance()를 호출함
초기화 순서를 보장하는 방법
- 프로그램 시작 시 여러 싱글턴의 getInstance()를 순서대로 호출
싱글턴의 변형
- 현재의 구현으로는 표현이 어려움
- 따라서 실무에서는 다르 변형을 사용하기도 함
- 디자인 패턴은 그저 가이드라인일 뿐
싱글턴의 변형 예
- 프로그램 실행 시
- getInstance()가 아니라 createInstance()를 호출
GraphicResourceManager.createInstance(loader, gfxDevice);
- 인스턴스가 필요할 때
- 매개변수가 없는 getInstance()를 호출
GraphicResourceManager gfxManager = GraphicResourceManager.getInstance();
- 프로그램 종료 시
- 더 이상 사용하지 않는 싱글턴 인스턴스 삭제 (메모리 해제)
GraphicResourceManager.deleteInstance();
안티패턴이란?
- 안티패턴이란 올바르지 않은 방법을 의미
- 즉, 배드 프랙티스를 의미
- 베스트 프랙티스의 반대말
- 안티패턴의 다른 예 : 매직 넘버, 매직 스트링
싱글턴은 안티패턴?
- 실질적으로 static과 똑같다는 이유로 욕하는 사람들이 잇음
- 싱글턴을 안 쓰고 같은 일을 할 수도 있음
- 하지만 쓸데없이 복잡해짐
- 모든 것이 개체여야만 하는 실용적 이유가 없으니 패스
- 훌륭한 프로그래머는 이런 무의미한 주장에 신경 쓰지 않음
--
내포 클래스
- 클래스 안에 다른 클래스
Java의 내포 클래스
- 내포 클래스
- 비정적 내포 클래스(=내부 클래스)
- 정적 내포 클래스
- C#, C++ 등의 언어에서는 정적 내포 클래스만 존재
- 그래서 보통 inner와 nested라는 용어를 혼용해서 사용
내포 클래스의 용도
- 서로 연관된 클래스들을 그룹 지을 수 있음
- 패키지로 그룹 짓는 것도 가능
- 하지만 클래스 속에 넣는 것이 더 긴밀한 그룹
- 내포 클래스는 바깥 클래스의 private 멤버에 접근 가능
- 하지만 그 반대의 경우는 불가능
별도 클래스 vs 비정적 내포 클래스
별도 클래스
public class Record {
byte[] rawData;
// ...
}
public class RecordReader {
private final Record record;
private int position;
public RecordReader(Record record) {
this.record = record;
}
// ...
}
비정적 내포 클래스
public class Record {
private final byte[] rawData;
public Record(byte[] rawData) {
this.rawData = rawData;
}
public class Reader {
private int position;
// ...
}
}
'프로그래머 > Java Managed Programming' 카테고리의 다른 글
[개체지향 프로그래밍] 상속 (0) | 2021.03.14 |
---|---|
[개체지향 프로그래밍] 개체 모델링 | 클래스 다이어그램 | 유연성 | OOP (0) | 2021.02.13 |
[개체지향 프로그래밍] 접근 제어자 | getter/setter | 캡슐화 | 추상화 (0) | 2021.02.07 |
[개체지향 프로그래밍] 개체 생성 | 가비지 콜렉터(garbage collector) | 생성자(constructor) (0) | 2021.02.07 |
[개체지향 프로그래밍] 클래스(class) | 접근 제어자(public, private) | 인스턴스(instance) (0) | 2021.02.07 |