09009
[Java] Singleton 본문
Singleton
"인스턴스가 오로지 단 하나만 존재할 수 있도록 클래스를 설계하는 것"
애플리케이션이 시작될 때, 어떤 클래스가 최초 한 번만 메모리를 할당(static)하고
해당 메모리에 인스턴스를 만들어 사용하고 공유하며 제한하는 패턴
Singleton은 '하나'의 인스턴스만 생성하여 사용하고 공유하는 디자인 패턴이다.
인스턴스가 필요할 경우 똑같은 인스턴스를 만들지 않고 기존의 인스턴스를 활용하는 것!
"단 하나의 객체만 만들도록 보장해야 하는 경우에 사용"
싱글톤을 만들기 위해서는 클래스 외부에서 new 연산자로 생성자를 호출할 수 없도록 해야 한다.
1) 생성자를 외부에서 호출할 수 없게 하기 위해서는 생성자 앞에 private 접근 제한자를 붙여준다.
2) 자신의 타입인 정적 필드 (static)를 하나 선언하고 자신의 객체를 생성하여 초기화한다.
3) 정적 필드 (static)에 private 접근 제한자를 붙여주어 외부에서 필드값을 변경하지 못하도록 막아야 한다.
4) 외부에서 호출 할 수 있는 정적 메서드 (ex. getInstance())를 선언하고 참조하고 있는 자신의 객체를 return해준다.
= 외부에서 객체를 얻는 유일한 방법: public 접근제한자를 붙인 정적 메서드 (ex. getInstance())를 호출하는 것
getInstance() 메서드는 단 하나의 객체만 return하므로 생성자를 여러 차례 호출하더라도
동일한 객체를 참조하고 실제로 생성되는 객체는 하나인 것이다.
즉, 싱글톤은 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나인 것을 의미함.
싱글톤 사용 이유: 고정된 메모리 영역에서 한번의 new로 인스턴스를 사용하기 때문에 메모리 낭비를 줄일 수 있다.
예시
public class 클래스 {
// 정적 필드
private static 클래스 single = new 클래스명();
// 생성자
private 클래스() { }
// 정적 메서드
public static 클래스 getInstance() {
return single;
}
}
✍ Single1.java
public class Single1 {
// static이 붙으면 클래스 로딩할 때 딱 1번 실행 -> 클래스 변수
private static Single1 instance = new Single1();
// private을 사용하면 외부에서 객체를 생성 못함.
Single1() {
}
// 처음에 생성된 instance를 같이 사용: singleton
// 객체를 생성할 때는 instasnce를 사용
public static Single1 getInstance() {
return instance;
}
}
위의 소스코드에서 Single1()을 보면 생성자 앞에 private 접근제한자를 붙이지 않은 것을 확인할 수 있는데 위와 같은 경우는 아래 소스코드 Single1Ex.java에서 시험삼아 클래스 외부에서 생성자를 호출할 수 있도록 private을 붙여주지 않은 것이다.
✍ Single1Ex.java
public class Single1Ex {
public static void main(String[] args) {
// 객체를 출력 패키지명.클래스명@해시코드
Single1 p1 = new Single1();
Single1 p2 = new Single1();
Single1 p3 = new Single1();
System.out.println(p1);
System.out.println(p2);
System.out.println(p3);
System.out.println("===============");
// 객체 이름은 다르지만 주소가 같다.
Single1 s1 = Single1.getInstance();
Single1 s2 = Single1.getInstance(); // 메소드를 통해서 객체 생성
Single1 s3 = Single1.getInstance();
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
// @ 뒤에는 주소임.
}
}
💻 출력
practice.Single1@246ae04d
practice.Single1@62043840
practice.Single1@5315b42e
===============
practice.Single1@2ef9b8bc
practice.Single1@2ef9b8bc
practice.Single1@2ef9b8bc
아래 소스코드에서 인스턴스 여러 개가 생성되는 것을 방지하려면
public class P4 {
public static void main(String[] args) {
StudentManager sm = new StudentManager();
StudentManager sm1 = new StudentManager();
StudentManager sm2 = new StudentManager();
sm.check();
}
}
class StudentManager {
// 아래는 클래스의 의도된 기능
public void add() {
}
public void check() {
}
}
1. 우선 생성자에 private의 제한을 둔다. (내부에서는 호출 가능, 외부에서는 호출 불가능, 내부에선 인스턴스 생성 가능)
2. 생성자를 private으로 두었지만 내부에서 인스턴스 1개는 생성해야 한다.
외부에서는 해당 인스턴스에 접근하게는 해야하지만 외부에서 생성하지 못하게 해야하므로 static으로 설정.
싱글톤의 메서드명은 일반적으로 getInstance()로 만든다.
private은 외부에서 막는 것. 내부에서는 생성 가능.
3. 최초 한 번만 생성하고 그 이후로는 못하게 하기
public class P4 {
public static void main(String[] args) {
// getInstance를 여러 번 호출해도 처음에만 인스턴스를 생성하고 그 이후에는 기존의 인스턴스 사용
StudentManager sm = StudentManager.getInstance();
StudentManager sm1 = StudentManager.getInstance();
StudentManager sm2 = StudentManager.getInstance();
sm.check();
}
}
class StudentManager {
private StudentManager() { }
private static StudentManager studentManager = null; // static 참조변수 생성
public static StudentManager getInstance() {
if (studentManager == null) { // 첫번째 호출일 때만
studentManager = new StudentManager(); // 인스턴스 생성
}
return studentManager;
}
// .. 내용 생략
}
개선 코드
class StudentManager {
private StudentManager() { }
private static StudentManager studentManager = new StudentManager();
public static StudentManager getInstance() {
return studentManager;
}
}
/
5/7
'Back-End > JAVA' 카테고리의 다른 글
[Java] 참조변수의 형변환 (1) | 2023.05.07 |
---|---|
[Java] SRP 원칙 (0) | 2023.05.03 |
[Java] static (0) | 2023.05.03 |
[Java] 변수 (0) | 2023.05.01 |
[Java] 고객 관리 (6) - 목록 확인 (0) | 2023.04.17 |