** 싱글턴 패턴이란? **
🌟 정의 / 특징
1. 싱글턴(singleton)이란 디자인 패턴 중 가장 간단한 패턴으로 '어떤 객체 하나'를 의미한다. 싱글턴 패턴은 프로그램에 클래스의 인스턴스가 딱 하나만 존재하도록 하는 디자인 패턴이다.
2. 외부 시스템과 상호작용하는 유틸리티 클래스 또는 전역 상태를 관리하는 클래스 구현에 적합하다.
- ex. 데이터 베이스 로드, 파일 시스템 로드, 공용 gui등(게임에서 팝업 창 or 툴팁창 ..), 로거(logger)
🔸 여기서 잠깐 !! 🔸
* 인스턴스와 객체의 차이는 무엇일까?
간단히 말해 객체는 선언이고 인스턴스는 실체화이다. 객체 지향 프로그래밍에서 해당 클래스의 구조로 컴퓨터 저장공간에 실제로 독립된 데이터 공간에 메모리를 가지게 되면 그것을 인스턴스화라고 말한다.
더 자세한 설명은 아래 블로그를 참고하길 바란다.
객체와 인스턴스의 차이::::kkennib (tistory.com)
객체와 인스턴스의 차이
* 자의적인 해석이므로 논란의 여지가 있음 객체와 인스턴스의 차이를 알아보니 블로그마다 말이 다르다. 어떤 블로거는 인스턴스는 객체와 같지만, 관계적인 측면에서 이야기할 때 객체 대신
cerulean85.tistory.com
🌟장점
단 한 번의 인스턴스 생성으로 메모리 관리가 편하고 객체 접근 시간이 줄어든다.
** 싱글턴 패턴의 문제점은? **
1. 싱글턴이 여러 개라면 프로그램을 구동할 때 원하는 순서로 초기화를 보장하기 힘들다.
→ 한 모듈에서 전역 객체를 참조할 때 그 전역 객체가 참조하는 또 다른 전역 객체가 아직 초기화가 안된 상태 일 수도 있다.
2. 의존 관계를 가리기 때문에 결합도가 높아지고(타이트 커플링 tight coupling) 단위 테스트가 복잡하다.
→ static 전역변수로 관리한다고 해서 인스턴스의 추가 생성을 막을 수가 없다.
🌟대책
1. static 카운터 변수를 두고 값이 증가 될 때 익셉션을 발생 시킨다.
2. 명시적으로 생성하는 것을 막는 방법으로 생성자를 private으로 선언하고 인스턴스를 리턴받기 위한 멤버함수를 만든다.
** 다양한 싱글턴 구현 방법들 **
1. 접근 제어 메커니즘과 static을 이용하여 클래스의 인스턴스를 하나만 생성하고 접근하게 만드는 방법
- static을 사용하는 이유? 싱글턴 클래스의 클라이언트는 언제든지 static 메서드인 instance( ) or getInstance( )를 호출해서 싱글턴 클래스의 인스턴스를 얻어와야하기 때문이다.
- instance( ) or getInstance( ) 메서드 안에 싱글턴의 로컬 static 인스턴스를 둔다. C++는 로컬에 둔 static 인스턴스가 스레드에 안전하게 초기화되도록 보장해준다. (단, 초기화할 때만 스레드에 안전하다는 점에 주의해야한다. 싱글턴의 메서드를 여러 스레드가 호출할 때는 각 메서드를 스레드에 안전하게 구현해야 한다. )
class Dataclass
{
protected:
// 기본 생성자 제어. 생성자가 protected이기 때문에 밖에서는 생성할 수가 없다.
Dataclass()
{
// ...
}
public:
static Dataclass& getInstance()
{
static Dataclass dataclass;
return dataclass;
// -- 힙 메모리 할당으로 객체를 생성하면 전체 객체가 아닌 포인터만 static으로 존재 --
// static Dataclass* dataclass = new Dataclass();
// return *dataclass;
}
Dataclass(Dataclass const&) = delete; /*복사 생성자 제어*/
Dataclass(Dataclass &&) = delete; /*이동 생성자 제어*/
Dataclass& operator=(Dataclass const&) = delete; /*복사 대입 연산자 제어*/
Dataclass& operator=(Dataclass&&) = delete; /*이동 대입 연산자 제어*/
~Dataclass();
// --> boost::noncopyable 클래스 : 이동생성자/연산자를 제외하고 모두 숨길수 있다.
};
2. 싱글턴 패턴 2번 째 문제점인 (인스턴스의 추가 생성을 막을 수가 없다.) 해결 하는 싱글턴
class DataClass
{
public:
DataClass()
{
static int instance_count{ 0 };
if (++instance_count > 1)
{
throw std::exception("Cannot make > 1 dataClass");
}
}
~DataClass();
};
DataClass& Get_DataClass()
{
static DataClass dataclass;
return dataclass;
}
public에 기본 생성자를 만들어 언제든지 인스턴스를 만드려고 시도 할 수 있으나 instance의 개수를 세고 있는 멤버변수로 제한을 두어 인셉션을 던지는 방법이다. 하지만, 1번의 방법을 추천한다.
**추가**
* 이건 왜 안될까?
누군가는 바보 같은 의문 일 수 있겠지만 단 한 번의 인스턴스를 생성하는데 왜 const를 붙이지 않을까? 라는 의문을 가진 적이 있다.
일단 이런 식으로 인스턴스를 만든다면, 리턴값의 모양은 static const가 될 것이다.
일단 먼저 여기서 알아야 할 선 지식은 const의 위치별 의미이다. const는 constant의 약자로 그 대상을 변경하지 않는다는 "상수"를 의미하고 "읽기 전용"을 의미한다.
- const Dataclass* dataclass --> Dataclass* dataclass을 상수화 하겠다. * dataclass이 가리키는 값이 상수가 되어 값을 변경할 수가 없다.
- Dataclass* const dataclass --> 포인터가 상수가 되므로 주소 값 변경이 불가능하다.
즉, dataclass에 있는 데이터를 수정할 수 없게 된다. 반환값이 const이기 때문에 값 자체로 사용할 때 사용하는게 맞다.
static const, 전역 상수는 컴파일러의 최적화에 의해 변수에 대한 공간을 예약해 두지 않는다. 리터럴과 다름없는 상수로 간주한다.
그럼 여기서 또 의문이 생긴다. 왜 .. static Dataclass* const 라고 하지 않는지... 아는 사람은 정확히 설명부탁드립니다
** 출처 **
1. 모던 c++ 디자인 패턴 / 드미트리 네스터룩 지음 / 출판사 : 깃벗
2. 전문가를 위한 c++ (개정 4판) : C++17 / 마크 그레고리 지음 / 출판사 : 한빛 미디어
'👨🏻💻 programming > ◽ 디자인 패턴' 카테고리의 다른 글
[디자인 패턴] 생성 패턴 - 1. 팩터리 Factory (0) | 2023.08.09 |
---|
안 하는 것 보다 낫겠지
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!