[Spring] Singleton Pattern
객체지향 디자인패턴 중 싱글턴 패턴은 객체의 인스턴스를 오직 1개만 생성한다. 이것이 싱글턴 패턴의 정의이다.
커넥션 풀, 스레드 풀, 디바이스 설정 객체 등과 같은 것을 인스턴스를 여러 개 만들어 사용하게 되면 불필요한 메모리 자원 낭비가 되는데, 이럴 때 사용하는 것이다.
이런 싱글턴 패턴을 구현하기 위해서는 반드시 객체 생성을 위한 new에 제약을 걸어야 한다. 또한 만들어진 단일 객체를 반환할 수 있는 메서드가 필요하다. 그래서 아래의 세 가지 조건이 필요하다.
- new를 외부에서 실행할 수 없도록 생성자에 private 접근 제어자를 지정한다.
- 유일한 단일 객체를 반환할 수 있는 정적 메서드가 필요하다.
- 유일한 단일 객체를 참조할 정적 참조 변수가 필요하다.
1) 싱글턴 패턴 예시 1
사람생성() 이라는 메서드를 통해서 하나의 인스턴스를 생성하고 이를 활용해서 나이를 설정하는 것이다.
만약, b사람이 생긴다고 하였을 때, 똑같이 .사람생성()을 호출한다면, a사람에 붙어있는 객체를 b사람도 참조하게 될 것이다.
//code.oa.gg/java8/1073
// 문제 : 사람객체를 생성한 후 나이를 22살로 만들어주세요.
// 조건 : 사람 생성자는 수정/추가할 수 없습니다.
// 조건 : 아래와 같이 출력 되어야 합니다.
class Main {
public static void main(String[] args) {
사람 a사람;
a사람 = 사람.사람생성();
a사람.set나이(22);
System.out.println("사람의 나이는 " + a사람.get나이() + "살 입니다.");
// 출력 : 사람의 나이는 22살 입니다.
}
}
class 사람 {
private int 나이;
private 사람() {
}
// 힌트 : 여기에 메서드 3개 추가해야 합니다.
public static 사람 사람생성(){
return new 사람();
}
void set나이(int 나이){
this.나이 = 나이;
}
int get나이(){
return 나이;
}
}
2) 싱글턴 패턴 예시 2
이 또한 위의 코드와 마찬가지로, 하나의 객체를 여러 배열에서 참조하고 있는 형식이다.
실제로 사람들[0]부터 사람들[4]에 들어있는 객체의 주소를 출력해보면 모두 동일한 것을 알 수 있다.
//code.oa.gg/java8/1075
// 문제 : 아래코드가 실행되도록 해주세요.
class Main {
public static void main(String[] args) {
사람[] 사람들 = new 사람[5];
사람들[0] = 사람.get사람();
사람들[1] = 사람.get사람();
사람들[2] = 사람.get사람();
사람들[3] = 사람.get사람();
사람들[4] = 사람.get사람();
System.out.println("실행완료");
}
}
class 사람{
private 사람(){
}
static 사람 get사람(){
return new 사람();
}
}
3) 싱글턴 패턴 예시 3
똑같은 객체를 참조하는데, 여기에서는 '번호'를 통해서 서로 다른 숫자를 가질 수 있도록 하고 있다.
어떤 숫자를 외부에서 집어넣어 바꾸는 것이 아니라, 클래스 내부적으로 호출이 몇 번 되느냐에 따라서 '번호'를 올리는 것이다.
숫자는 다르게 프린트 되지만, 결국은 모두 같은 객체를 참조하고 있음을 알아야 한다.
//code.oa.gg/java8/1078
// 문제 : 아래코드가 실행되도록 해주세요.[정답]
class Main {
public static void main(String[] args) {
사람[] 사람들 = new 사람[5];
사람들[0] = 사람.get사람();
사람들[1] = 사람.get사람();
사람들[2] = 사람.get사람();
사람들[3] = 사람.get사람();
사람들[4] = 사람.get사람();
for ( int i = 0; i < 사람들.length; i++ ) {
사람들[i].자기소개();
}
/*
// 출력
저는 1번째 사람입니다.
저는 2번째 사람입니다.
저는 3번째 사람입니다.
저는 4번째 사람입니다.
저는 5번째 사람입니다.
*/
}
}
class 사람 {
static private int 사람수;
private int 번호;
// static 요소 전용 생성자
// 따로 뭔가를 호출하지 않아도 프로그램이 실행되면 가장먼저 실행된다.
static {
사람수 = 0;
}
private 사람(int 번호) {
this.번호 = 번호;
}
static 사람 get사람() {
사람 a사람 = new 사람(사람수 + 1);
사람수++;
return a사람;
}
public void 자기소개() {
System.out.println("저는 " + 번호 + "번째 사람입니다.");
}
}
4) 싱글턴 패턴 예시 4
여기도 마찬가지로 똑같은 객체를 참조한다. static 필드를 통해서 일정 조건이 되면 더 이상 숫자가 올라가지 않게 제한을 둔 것이 전부이다. 숫자는 다르게 프린트 되지만, 결국은 모두 같은 객체를 참조하고 있음을 알아야 한다.
//code.oa.gg/java8/1079
// 문제 : 아래코드가 실행되도록 해주세요.
// 조건 : 사람 객체의 수는 3을 넘을 수 없습니다.
class Main {
public static void main(String[] args) {
사람[] 사람들 = new 사람[7];
사람들[0] = 사람.get사람();
사람들[1] = 사람.get사람();
사람들[2] = 사람.get사람();
사람들[3] = 사람.get사람();
사람들[4] = 사람.get사람();
사람들[5] = 사람.get사람();
사람들[6] = 사람.get사람();
for ( int i = 0; i < 사람들.length; i++ ) {
사람들[i].자기소개();
}
/*
// 출력
저는 1번째 사람입니다.
저는 2번째 사람입니다.
저는 3번째 사람입니다.
저는 3번째 사람입니다.
저는 3번째 사람입니다.
저는 3번째 사람입니다.
저는 3번째 사람입니다.
*/
}
}
class 사람 {
private int id;
private static int lastId;
private static 사람 가장_마지막에_생성된_사람;
static {
lastId = 0;
}
public static 사람 get사람() {
if ( lastId == 3 ) {
return 가장_마지막에_생성된_사람;
}
int id = ++lastId;
사람 a사람 = new 사람(id);
가장_마지막에_생성된_사람 = a사람;
return a사람;
}
public 사람(int id) {
this.id = id;
}
public void 자기소개() {
System.out.printf("저는 %d번째 사람입니다.\n", id);
}
}
5) 싱글턴 패턴의 단점
싱글턴 패턴은 객체 지향 설계 원칙(SOLID) 중 개방-폐쇄 원칙에 위배될 수 있는 한계점을 가지고 있다.
싱글턴 인스턴스가 혼자 많은 일을 하거나, 많은 데이터를 공유시키면, 다른 클래스와 결합도가 높아지게 되는데, 이때, 개방-폐쇄 원칙이 위배된다. 결합도가 높아지면 유지보수가 힘들고, 결과적으로 테스트도 원활하게 진행할 수 없는 문제점이 발생한다.
또한 멀티 스레드 환경에서 동기화 처리를 하지 않았을 때, 인스턴스가 2개 생성되는 문제도 발생할 수 있다.
'Web' 카테고리의 다른 글
[Spring] Observer Pattern (0) | 2022.07.24 |
---|---|
[Spring] Factory-Method Pattern (0) | 2022.07.23 |
[Java] equals()와 ==의 차이점 (0) | 2022.07.19 |
[Java] Wrapper 클래스 (0) | 2022.07.18 |
[Java] throws (0) | 2022.07.17 |
댓글