티스토리 뷰

디자인 패턴이란 ?

위키에서는 다음과 같이 정의한다. 

 

 

말을 어렵게 정의해놓은 것 같다. 좀 더 쉽게 말하자면,

프로그램을 한번에 딱딱 설계하는 것은 상당히 힘들다. 프로그램을 설계할 때는 어떠한 목적을 가지고 있으며, 어떤 기능이 있고 어떻게 동작하는지 등등을 깊게 고민해봐야 한다. 이런 머리아픈 고민들을 덜어내는 것이 디자인 패턴이다. 설계할 때는 다양한 문제들을 만나게 된다. 만약 엄청난 집중력으로 문제들을 풀 방법을 생각해냈다면, 한번 디자인 패턴과 비교해보자. 아예 똑같진 않더라도 해결 방법에 디자인 패턴 개념이 응용되었을 경우가 분명히 있을 것이다.

무슨 말이냐면 디자인 패턴은 이미 설계를 하면서 다양한 문제상황들을 만난 개발쌉고수들이 "이거 다른 개발자가 이 문제를 만나면 머리 좀 아프겠는데?" 하면서 정규화된 방법(패턴)으로 정리해 놓은 것이다. 정리하자면 프로그램 설계자가 좀 더 올바른 방법으로 빠르게 설계하도록 도와주는 것이 바로 디자인 패턴이다. 이번 포스팅에서는 디자인 패턴 중 하나인 싱글톤 패턴을 알아본다. 

 

 

싱글톤 패턴이란 ?

싱글톤 패턴은 하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴이다. 처음에는 무슨말인지 몰랐다. "원래 기본적으로 클래스는 하나의 인스턴스를 가지고 있는게 아니었나?" 라고 생각했다. 하지만 방금 질문처럼 접근하면 이해하기가 어렵다. 롤을 생각해보자. 롤에서 설정화면은 단 한개다. 만약 여러 설정화면이 있다고 가정을 해보자. 게임을 시작하기 전에 공격설정을 a(기본값)에서 space로 바꾸고 게임을 돌렸다. 그런데 공격이 space로 바뀌지 않고 a로 되어있다면 혼란이 올 것이다. 즉, 메인화면에서의 설정화면과 인게임에서의 설정화면은 다른 것이다. 이렇게 오직 하나의 인스턴스만 가져야 하는 경우들이 있다. 한번 코드로 예시를 들어보겠다. 

 

아래는 Setting이라는 클래스가 있다. 

public class Setting {

}

 

그리고 Main 클래스가 있다.  Main 클래스에서는 Setting 클래스 인스턴스를 얼마든지 생성할 수 있다. 

public class Main {
	public static void main(String[] args) {
    	Setting setting = new Setting();
    }
}

 

Play 클래스에서도 Setting 클래스 인스턴스를 생성할 수 있다.

public class Play {
	public static void main(String[] args) {
    	Setting setting = new Setting();
    }
}

 

여기서 중요한 점은 위에서 말했다시피 두 인스턴스가 같지 않다. 그럼 Main 클래스에서 바꾼 설정과 Play 클래스에서 바꾼 설정이 다르게 된다. 그래서 개발쌉고수들은 "여기서 어떻게 하면 두 인스턴스가 아니라 하나의 인스턴스로 바꿀 수 있을까 ? "라고 생각했고, 그 해결방법(패턴)의 이름이 바로 싱글톤 패턴이다. 

 

 

싱글톤 패턴 구현

그럼 어떻게 해야 하나의 인스턴스로 바꿀 수 있을까 ? 결론부터 말하자면 new로 생성하는 것이 아닌 클래스에 인스턴스를 생성하고 변수에 저장한 후 메서드로 사용하면 된다. 말보단 코드로 보는 것이 빠르니 흐름대로 보도록 하겠다.

 

 

1. 접근제어자로 new 생성 막기

new 생성을 막는 방법은 생성자를 접근제어자를 통해 외부 클래스에 사용하지 못하도록 설정하면 된다. 

public class Setting {

	private Setting() {}
}

 

그럼 new로 생성한 부분이 컴파일에 걸리게 된다.

 

 

2.  메서드로 인스턴스 만들어주기

더이상 Setting 클래스 밖에선 생성자를 사용할 수 없기 때문에 함부로 인스턴스를 만들지 못하게 된다. 우리가 private로 설정한 변수는 getter 메서드로 접근하는 것처럼 인스턴스 생성을 메서드를 통해서 만들게 해주면 된다.

public class Setting {

	private Setting() {}
    
    public static Setting getInstance() {
    	return new Setting();
    }
}

 

이렇게 해주면 Main 클래스와 Play 클래스에서는 아래와 같이 사용할 수 있다. 

public class Main {
	public static void main(String[] args) {
    	Setting setting = Setting.getInstance();
    }
}
public class Play {
	public static void main(String[] args) {
    	Setting setting = Setting.getInstance();
    }
}

 

하지만 역시 메서드를 보면 new생성자로 생성하기 때문에 Main클래스의 setting과 Play클래스의 setting은 서로 다르다. 

 

 

3. 한개의 인스턴스만 가지기

결국 Main클래스의 setting과 Play클래스의 setting를 같게 하기 위해서는 다음과 같이 할 수 있다.

public class Setting {

	private static Setting instance;

	private Setting() {}
    
    public static Setting getInstance() {
    	if(instance == null) {
        	instance = new Setting();
        }
    	return instance;
    }
}

 

static 변수를 만들어주고 만약 null이라면 새로운 인스턴스를 만들어주고 아니라면 기존의 인스턴스를 반환해준다. 

이러면 무한대로 Setting 인스턴스를 생성해도 같은 인스턴스가 생성된다. 

 

 

싱글톤 패턴의 단점

싱글톤 패턴은 장점이 단점이 될 수 있다. 바로 TDD를 할 때인데, TDD 단위테스트는 각 테스트들이 독립적이어야 하고, 순서에 의존하지 않아야 한다. 하지만 싱글톤 패턴으로 인해 테스트할 인스턴스들이 같다면 문제가 될 수 있다. 이를 해결하는 방법은 의존성 주입 방식을 이용하면 된다. 

 

 

싱글톤 패턴과 의존성 주입의 차이점

의존성 주입의 개념과 동작과정은 자동 의존성 주입직접 의존성 주입 포스팅을 참고하면 된다. 결국 의존성 주입은 싱글톤 패턴에서 파생된 것이라고 보면 된다. 클래스 간의 의존성이 강하게 되어있는 것을 느슨하게 풀어줌으로써 테스팅하기가 쉽고 간편하다. 

 

우리는 싱글톤 패턴이 클래스 간의 의존성이 강하게 되어있다고 했다. Setting클래스와 Main, Play 클래스만 보더라도 Setting클래스에서 직접 인스턴스를 생성하는 방식이기 때문이다. 하지만 의존성 주입(DI)은 의존성을 주입해주는 의존성 주입자가 대신 인스턴스를 생성해주기 때문에 상위클래스(위 예제에서는 Setting 클래스)는 의존성이 떨어진다. 이를 '디커플링이 된다.' 라고도 한다. 대표적으로 스프링에서의 의존성주입은 스프링 빈이 상위 모듈이고, 스프링 빈을 의존성 주입자인 스프링컨테이너에 저장해두었다가 스프링컨테이너가 주입해주는 방식이다.

 

'Design Pattern' 카테고리의 다른 글

이론 말고 실제 코드에 MVC 패턴 적용시켜보기  (1) 2022.11.17
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday