딱 하나의 인스턴스만 존재할 수 있는 클래스를 만들고 싶었던 적이 있으신가요?
있다면, 없다면, 아니면 애매하다면?
바로 그것이 싱글톤 패턴(Singleton Pattern)입니다.
패턴 자체에는 문제가 없습니다. 하지만 일부 개발자들은 이를 안티 패턴(anti-pattern)이라고 부르기도 하는데, 이는 잘못된 설계를 정당화하는 핑계로 남용될 수 있기 때문입니다.
그럼 실제 코드 예제를 통해 싱글톤 패턴이 어떻게 동작하는지 살펴보겠습니다.
싱글톤 패턴 코드 예제
싱글톤 패턴의 핵심 아이디어는 단순합니다. 오직 하나의 인스턴스만 갖는 클래스를 만드는 것이죠.
구현 방법은 다음과 같습니다:
new메서드를 private으로 선언하여 외부에서 객체 생성을 막습니다.- 클래스의 유일한 인스턴스를 반환하는
instance라는 이름의 클래스 메서드를 정의합니다.
다행히도 싱글톤은 널리 알려진 디자인 패턴이기 때문에, Ruby 표준 라이브러리에는 어떤 클래스에든 include할 수 있는 Singleton 모듈이 내장되어 있습니다.
사용 방법은 다음과 같습니다:
require 'singleton' class Shop include Singleton end
이제 Shop.new로 객체를 생성하려고 하면 다음과 같은 에러가 발생합니다.
Shop.new # NoMethodError: private method `new' called for Shop:Class
Shop의 유일한 객체에 접근하려면 instance 메서드를 사용하면 됩니다.
Shop.instance.object_id # 5659218 Shop.instance.object_id # 5659218
object_id가 항상 동일하게 유지되는 것으로 보아, 매번 같은 객체가 반환된다는 것을 확인할 수 있습니다.
기억해야 할 점:
싱글톤은 매우 단순한 패턴입니다. 객체 생성을 단 하나로 제한하고, 필요할 때 언제든 그 객체를 요청할 수 있다는 것이 핵심입니다.
싱글톤 패턴을 피해야 하는 이유
싱글톤 패턴은 종종 일종의 전역 변수(global variable)를 만들기 위한 핑계로 사용됩니다. 우리 모두 알다시피 전역 변수는 통제하기 어렵기 때문에 좋지 않습니다. 이는 테스트를 어렵게 만들고, 코드 간 결합도(coupling)를 높일 수 있습니다.
"싱글톤의 진짜 문제는 객체의 적절한 가시성(visibility)을 신중하게 고민하지 않아도 되는 너무 좋은 핑계를 제공한다는 것입니다." – Kent Beck
여러분의 대부분의 클래스가 특정 객체 하나에 의존하는 상황을 상상해 보세요. 바로 그것이 싱글톤 패턴이 초래할 수 있는 결과입니다. 나중에 리팩토링하려면 큰 어려움에 직면하게 될 것입니다.
그렇다면, 이 패턴의 좋은 활용 사례는 없을까요?
Github에서 검색해 보면, 싱글톤 패턴을 널 객체 패턴(Null Object Pattern)과 함께 사용하는 저장소들을 찾을 수 있습니다. 이 조합은 꽤 합리적입니다. 실제로 Rails도 ActionPack의 일부에서 이 방식을 사용합니다.
실제 Rails 코드 예제입니다:
class AllType < Type
include Singleton
def initialize
super "*/*", :all
end
def all?; true; end
def html?; true; end
end
이 코드는 Type 클래스를 상속받는 AllType 클래스입니다.
instance 메서드를 통해 AllType 객체를 처음 생성하면 super가 호출되어 초기화된 객체가 반환됩니다. 그 이후 instance를 호출할 때마다 항상 동일한 객체를 받게 됩니다.
결론적으로:
네, 싱글톤 패턴은 적절한 상황에서 유용할 수 있습니다. 하지만 충분히 고민하지 않은 채 무작정 사용해서는 안 됩니다. 사용 여부를 결정하기 전에 설계상의 장단점을 신중하게 검토하세요.
마치며: 핵심 요약
이번 글에서는 싱글톤 디자인 패턴이 무엇인지, Ruby에서 어떻게 구현하는지, 그리고 왜 대부분의 경우 이 패턴을 피하는 것이 좋은지 배웠습니다.
- 구현 방법: Ruby 표준 라이브러리의
Singleton모듈을 include하면 됩니다. - 장점: 객체 생성을 하나로 제한하여 일관된 상태를 유지할 수 있습니다.
- 단점: 전역 변수와 유사하게 작동하여 테스트가 어려워지고 결합도가 높아질 수 있습니다.
- 권장 사항: Null Object 패턴과의 조합처럼 명확한 근거가 있을 때만 신중하게 사용하세요.
이 패턴에 대해 어떻게 생각하시나요? 실제로 사용해 본 경험이 있으신가요? 댓글로 의견을 공유해 주세요 🙂
읽어주셔서 감사합니다!