[Design Pattern] 싱글턴 패턴(Singleton Pattern)
Posted: Updated:
자바 디자인 패턴 스터디를 하며 ‘Java 객체 지향 디자인 패턴’ 교재를 정리한 글입니다.
싱글턴 패턴(Singleton Pattern)
- 인스턴스가 오직 하나만 생성되는 것을 보장
- 어디서든 이 인스턴스에 접근 가능
- ‘단 하나의 원소만을 가진 집합’ 이라는 수학 이론에서 유래
- 클라이언트가 싱글턴 클래스에
getInstance
메서드를 통해 객체 생성을 요청 - 이미 객체가 생성된 경우 객체를 반환
- 처음 생성하는 경우 생성자를 호출해 객체 생성
예시: 프린터 관리자 만들기
Printer
클래스를 사용한 프로그램Printer
는 반드시 하나
단일 스레드 환경에서의 싱글턴
구현 방법
- 외부에서 생성자를 호출할 수 없음
- 생성자를
private
로 선언 - 인스턴스를 만들어 제공하는 메서드 생성
- 생성자를
- 인스턴스가 이미 생성되어 있는지 검사
- 생성되지 않은 상황이면 생성자 호출해 인스턴스 생성
- 이미 생성되었다면 참조하는 인스턴스 반환
printer
변수,getPrinter
메서드는static
타입으로 선언
전체 코드
- 5명의 사용자가 프린터를 이용하는 상황
public class User {
private String name;
public User(String name) {
this.name = name;
}
public void print() {
Printer printer = Printer.getPrinter();
printer.print(this.name + " print using " + printer.toString() + ".");
}
}
public class Printer {
private static Printer printer = null;
private Printer() { }
public static Printer getPrinter() {
if (printer == null) {
printer = new Printer();
}
return printer;
}
public void print(String str) {
System.out.println(str);
}
}
public class Main {
private static final int User_NUM = 5;
public static void main(String[] args) {
User[] user = new User[User_NUM];
for (int i = 0; i < User_NUM; i++) {
user[i] = new User((i + 1) + "-user");
user[i].print();
}
}
}
출력
1-user print using Printer@6aaa5eb0.
2-user print using Printer@6aaa5eb0.
3-user print using Printer@6aaa5eb0.
4-user print using Printer@6aaa5eb0.
5-user print using Printer@6aaa5eb0.
다중 스레드 환경에서의 싱글턴
정적 변수에 인스턴스를 만들어 바로 초기화
- 클래스가 메모리에 로딩될 때 만들어져 초기화 한 번만 실행
- 정적 메서드
getPrinter
를 통해 참조되는 인스턴스를 얻을 수 있음
Printer 클래스 코드
public class Printer {
private static Printer printer = new Printer();
private int counter = 0;
private Printer() { }
public static Printer getPrinter() {
return printer;
}
public void print(String str) {
counter++;
System.out.println(str);
}
}
getPrinter 메서드 동기화
synchronized
사용 👉 여러 스레드가 하나의 자원을 사용하고자 할 때, 현재 데이터를 활용하고 있는 스레드 외의 다른 스레드들은 데이터에 접근할 수 없도록 막음
Printer 클래스 코드
public class Printer {
private static Printer printer = null;
private int counter = 0;
private Printer() { }
public synchronized static Printer getPrinter() {
if (printer == null) {
printer = new Printer();
}
return printer;
}
public void print(String str) {
synchronized (this) {
counter++;
System.out.println(str+counter);
}
}
}
정적 클래스
- 정적 메서드로 이루어진 정적 클래스
- 굳이 싱글톤 패턴을 사용하지 않아도 동일한 효과를 얻을 수 있음
- 객체를 생성하지 않고 메서드를 사용
- 인터페이스에서는 사용할 수 없음
정적 클래스로 구현한 예제
- 객체를 전혀 생성하지 않으며 메서드를 사용함
- 정적 메서드를 사용하여 인스턴스 메서드를 사용하는 것보다 성능 면에서 우수
전체 코드
public class Printer {
private static int counter = 0;
public synchronized static void print(String str) {
counter++;
System.out.println(str + counter);
}
}
public class UserThread extends Thread{
public UserThread(String name) {
super(name);
}
public void run() {
Printer.print(Thread.currentThread().getName()+" print using .");
}
}
public class Main {
private static final int THREAD_NUM = 5;
public static void main(String[] args) {
UserThread[] user = new UserThread[THREAD_NUM];
for (int i = 0; i < THREAD_NUM; i++) {
user[i] = new UserThread((i+1)+"-thread");
user[i].start();
}
}
}
출력
2-thread print using .1
1-thread print using .2
4-thread print using .3
3-thread print using .4
5-thread print using .5
댓글남기기