A A
[Design Pattern] Singleton Pattern - 싱글톀 νŒ¨ν„΄ & Metaclass

Singleton Pattern

Singleton νŒ¨ν„΄μ€ 클래슀의 μΈμŠ€ν„΄μŠ€κ°€ ν•˜λ‚˜λ§Œ μƒμ„±λ˜λ„λ‘ 보μž₯ν•˜κ³ , κ·Έ μΈμŠ€ν„΄μŠ€μ— μ ‘κ·Όν•  수 μžˆλŠ” μ „μ—­ 접근점을 μ œκ³΅ν•˜λŠ” νŒ¨ν„΄μž…λ‹ˆλ‹€.
  • 그리고 νŠΉμ • 클래슀의 μΈμŠ€ν„΄μŠ€κ°€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ „μ²΄μ—μ„œ ν•˜λ‚˜λ§Œ μ‘΄μž¬ν•΄μ•Ό ν•  λ•Œ μ‚¬μš©λ©λ‹ˆλ‹€.
  • λ˜ν•œ νŠΉμ§•λ“€μ„ μ•„λž˜μ— μ μ–΄λ³΄μžλ©΄.
    • ν΄λž˜μŠ€μ— λŒ€ν•œ 단일 객체λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€.
    • μ „μ—­ 객체λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€.
    • 곡유된 λ¦¬μ†ŒμŠ€μ— λŒ€ν•œ λ™μ‹œ μ ‘κ·Ό μ œμ–΄κ°€ κ°€λŠ₯ν•©λ‹ˆλ‹€.
    • κΈ€λ‘œλ²Œ μ—‘μ„ΈμŠ€ 지점을 μ œκ³΅ν•˜λŠ”, 단점이 거이 μ—†λŠ” κ²€μ¦λœ νŒ¨ν„΄μž…λ‹ˆλ‹€.

  • μœ„μ˜ λ‹€μ΄μ–΄κ·Έλž¨μ„ μ˜ˆμ‹œλ‘œ 보면, μƒμ„±μžλ₯Ό private둜 μ„ μ–Έν•˜κ³ , 객체λ₯Ό μ΄ˆκΈ°ν™” ν•˜λŠ” static ν•¨μˆ˜λ₯Ό λ§Œλ“€μ–΄ κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • 첫 ν˜ΈμΆœμ— 객체가 μƒμ„±λ˜κ³ , κ·Έν›„ ν΄λž˜μŠ€λŠ” λ™μΌν•œ 객체λ₯Ό 계속 λ°˜ν™˜ν•©λ‹ˆλ‹€.
class Singleton(object):
    def __new__(cls):

        if not hasattr(cls, 'instance'):
            print('create')
            cls.instance = super(Singleton, cls).__new__(cls)
        else:
            print('recycle')
        return cls.instance

s1 = Singleton()
print(s1)

s2 = Singleton()
print(s1)

print(s1 is s2)

μ‹€ν–‰κ²°κ³Ό μž…λ‹ˆλ‹€.

  • μœ„μ˜ μ½”λ“œλ₯Ό 보면 ν•œ 개의 Singleton 클래슀 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€.
  • 이미 μƒμ„±λœ μΈμŠ€ν„΄μŠ€κ°€ μžˆλ‹€λ©΄ μž¬μ‚¬μš© ν•©λ‹ˆλ‹€.

 

핡심 κ°œλ…

  1. κ³ μœ ν•œ μΈμŠ€ν„΄μŠ€ 보μž₯: Singleton ν΄λž˜μŠ€λŠ” μΈμŠ€ν„΄μŠ€κ°€ ν•˜λ‚˜λ§Œ μƒμ„±λ˜λ„λ‘ ν•©λ‹ˆλ‹€.
  2. μ „μ—­ 접근점 제곡: Singleton ν΄λž˜μŠ€λŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ „μ²΄μ—μ„œ μΈμŠ€ν„΄μŠ€μ— μ ‘κ·Όν•  수 μžˆλŠ” 방법을 μ œκ³΅ν•©λ‹ˆλ‹€.
  3. 게으λ₯Έ μ΄ˆκΈ°ν™”: μΈμŠ€ν„΄μŠ€κ°€ μ‹€μ œλ‘œ ν•„μš”ν•  λ•ŒκΉŒμ§€ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜μ§€ μ•ŠλŠ” 방식을 μ‚¬μš©ν•©λ‹ˆλ‹€.

 

μž₯점

  • 고유 μΈμŠ€ν„΄μŠ€ 보μž₯: νŠΉμ • 클래슀의 μΈμŠ€ν„΄μŠ€κ°€ ν•˜λ‚˜λ§Œ μ‘΄μž¬ν•¨μ„ 보μž₯ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • μ „μ—­ μƒνƒœ 곡유: μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ „μ—­μ—μ„œ μ ‘κ·Ό κ°€λŠ₯ν•œ μΈμŠ€ν„΄μŠ€λ₯Ό 톡해 μƒνƒœλ₯Ό κ³΅μœ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • μΈμŠ€ν„΄μŠ€ 관리 용이: μΈμŠ€ν„΄μŠ€μ˜ 생성과 접근을 μ€‘μ•™μ—μ„œ 관리할 수 μžˆμŠ΅λ‹ˆλ‹€.

 

단점

  • κΈ€λ‘œλ²Œ μƒνƒœ μ‚¬μš©: μ „μ—­ μΈμŠ€ν„΄μŠ€λ₯Ό μ‚¬μš©ν•˜λ―€λ‘œ, μƒνƒœλ₯Ό κ³΅μœ ν•˜λŠ” 방식이 λ°”λžŒμ§ν•˜μ§€ μ•Šμ€ 경우 λ¬Έμ œκ°€ 될 수 μžˆμŠ΅λ‹ˆλ‹€.
  • ν…ŒμŠ€νŠΈ 어렀움: 싱글톀 μΈμŠ€ν„΄μŠ€λŠ” μ „μ—­ μƒνƒœλ₯Ό κ°€μ§€λ―€λ‘œ, μœ λ‹› ν…ŒμŠ€νŠΈμ—μ„œ λ‹€λ₯Έ ν…ŒμŠ€νŠΈ κ°„μ˜ μƒνƒœ 곡유둜 인해 ν…ŒμŠ€νŠΈκ°€ μ–΄λ €μšΈ 수 μžˆμŠ΅λ‹ˆλ‹€.
  • λ©€ν‹°μŠ€λ ˆλ“œ ν™˜κ²½ 문제: λ©€ν‹°μŠ€λ ˆλ“œ ν™˜κ²½μ—μ„œ 동기화 문제둜 인해 μΈμŠ€ν„΄μŠ€κ°€ μ—¬λŸ¬ 개 생성될 수 μžˆμŠ΅λ‹ˆλ‹€.

Singleton & Metaclass

Metaclassλ₯Ό κ°„λ‹¨νžˆ μ„€λͺ…ν•˜μžλ©΄, 클래슀λ₯Ό λ§Œλ“œλŠ” 클래슀라고 ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • type은 객체의 클래슀 μ’…λ₯˜λ₯Ό μ•Œμ•„λ‚Ό λ•Œλ„ μ‚¬μš©λ˜μ§€λ§Œ, 클래슀λ₯Ό λ§Œλ“€μ–΄ λ‚Ό μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.
  • type을 μƒμ†λ°›κ²Œ 되면, λ©”νƒ€ν΄λž˜μŠ€κ°€ 되며, 주둜 클래슀의 λ™μž‘μ„ μ œμ–΄ν•  λ•Œ μ‚¬μš©λ©λ‹ˆλ‹€.
  • 메타 ν΄λž˜μŠ€λŠ” call ν•¨μˆ˜λ₯Ό ν†΅ν•˜μ—¬ 객체 생성에 κ΄€ν•œ μ œμ–΄λ₯Ό ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
# example
class λ©”νƒ€ν΄λž˜μŠ€μ΄λ¦„(type):
	def _new_(metacls, name, bases, namespace):
		code

 

 

MetaClass의 λ™μž‘

class MyInt(type):

    def _call_(cls, *args, **kwds):
        print("myint", args)
        print("Now do whatever you want with these objects...")
        return type.__call__(cls, *args, **kwds)
    
class int(metaclass=MyInt):
    def _init_(self, x, y):
        self.x = x
        self.y = y

i = int(4, 5)

μœ„ μ½”λ“œμ˜ μ‹€ν–‰κ²°κ³Ό μž…λ‹ˆλ‹€.

  • call MethodλŠ” 이미 μ‘΄μž¬ν•˜λŠ” 클래슀의 객체λ₯Ό 생성할 λ•Œ ν˜ΈμΆœλ˜λŠ” 파이썬의 특수 Method μž…λ‹ˆλ‹€.
  • int 클래슀λ₯Ό μƒμ„±ν•˜λ©΄ MyInt λ©”νƒ€ν΄λž˜μŠ€μ˜ call Methodκ°€ ν˜ΈμΆœλ©λ‹ˆλ‹€.
  • 객체 생성을 λ©”νƒ€ν΄λž˜μŠ€κ°€ μ œμ–΄ν•œλ‹€λŠ” μ˜λ―Έμž…λ‹ˆλ‹€.
λ©”νƒ€ν΄λž˜μŠ€κ°€ ν΄λž˜μŠ€μ™€ 객체 생성을 μ œμ–΄ ν•œλ‹€λ©΄ 싱글톀을 μƒμ„±ν•˜λŠ” μš©λ„λ‘œ μ‚¬μš©ν•  수 μžˆλ‹€λŠ” μ˜λ―Έκ°€ λ©λ‹ˆλ‹€.

 

class MetaSingleton(type):
    _instances = {}

    def __call__(cls, *args, **kwds):
        if cls not in cls._instances:
            cls._instances[cls] = super(MetaSingleton, cls).__call__(*args, **kwargs)
        
        return cls._instances[cls]

class Box(metaclass=MetaSingleton):
    pass

b1 = Box()
b2 = Box()

print(b1 == b2)
  • λ©”νƒ€ν΄λž˜μŠ€μ˜ call ν•¨μˆ˜ 내뢀에 μΈμŠ€ν„΄μŠ€ 생성여뢀λ₯Ό ν™•μΈν•˜λŠ” 둜직이 있으며, λ©”νƒ€ν΄λž˜μŠ€μ— μ˜ν•΄ Singleton으둜 μ§€μ •λœ Box 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό 생성될 λ•Œ Metaclass의 call ν•¨μˆ˜κ°€ ν˜ΈμΆœλ˜λ©΄μ„œ Box의 생성을 μ œμ–΄ν•©λ‹ˆλ‹€.
  • μ΄λ•Œ, Singleton μ„±μ§ˆμ„ κ°€μ§€κ²Œ λ©λ‹ˆλ‹€.

Singleton Pattern ν™œμš© 사둀

DBλ₯Ό ν™œμš©ν•˜λŠ” ν΄λΌμš°λ“œ μ„œλΉ„μŠ€λ₯Ό μƒκ°ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.
  • ν΄λΌμš°λ“œ μ„œλΉ„μŠ€ λ‚΄ DB에 μ ‘κ·Όν•˜λŠ” μ—¬λŸ¬κ°œμ˜ λͺ¨λ“ˆμ΄ μžˆμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.
  • μ—¬λŸ¬ 개의 μ„œλΉ„μŠ€κ°€ ν•œ 개의 DBλ₯Ό κ³΅μœ ν•˜κ³  μžˆλŠ” ꡬ쑰λ₯Ό λ– μ˜¬λ¦¬λ©΄ λ©λ‹ˆλ‹€.
import sqlite3

class MetaSingleton(type):
    _instances = {}

    def __call__(cls, *args, **kwds):
        if cls not in cls._instances:
            cls._instances[cls] = super(MetaSingleton, cls).__call__(*args, **kwargs)
        
        return cls._instances[cls]

class Database(metaclass=MetaSingleton):
    connection = None
    def connest(self):
        if self.connection is None:
            self.connection = sqlite3.connect('db.sqlite3')
            self.cursorobj = self.connection.cursor()
        return self.cursorobj

db1 = Database().connect()
db2 = Database().connect()

print(db1, db2)

Monostate Singleton Pattern

Monostate Sington Pattern은 λͺ¨λ“  객체가 같은 μƒνƒœκ°€ κ³΅μœ ν•˜λŠ” νŒ¨ν„΄ μž…λ‹ˆλ‹€.
  • Singleton Pattern의 μ •μ˜λŠ” λ°˜λ“œμ‹œ ν•œκ°œμ˜ 클래슀 객체만 μ‘΄μž¬ν•΄μ•Όν•¨
  • ν•˜μ§€λ§Œ, Alex MartelliλŠ” μƒνƒœλ₯Ό κ³΅μœ ν•˜λŠ” μΈμŠ€ν„΄μŠ€κ°€ ν•„μš”ν•˜λ‹€κ³  μ£Όμž₯ ν–ˆμŠ΅λ‹ˆλ‹€.
    • 객체의 생성여뢀보닀, 객체의 μƒνƒœμ™€ ν–‰μœ„κ°€ 더 μ€‘μš”ν•˜λ‹€κ³  μƒκ°ν–ˆκΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.
class MonoState:
    __shared_state = {}

    def __init__(self):
        self.__dict__ = self.__shared_state
        self.x = 1
        self.y = 2
        self.z = 3

        pass

ms1 = MonoState()
ms2 = MonoState()

print(ms1)
print(ms2)

ms2.x = 20
ms1.y = 20
ms2.z = 30

print(ms1.x, ms1.y, ms1.z)
print(ms2.x, ms2.y, ms2.z)
print(ms1.__dict__)
print(ms2.__dict__)

Pythonμ—μ„œ λͺ¨λ“  λͺ¨λ“ˆλ“€μ€ Singleton

Python의 import 방식 λ•Œλ¬Έμ— λͺ¨λ“  λͺ¨λ“ˆλ“€μ„ 기본적으둜 singleton μž…λ‹ˆλ‹€.
  • ν•œλ²ˆ 파이썬의 μž‘λ™λ°©μ‹μ„ μ‚΄νŽ΄λ³΄λ©΄,
    • python module이 import λ˜μ—ˆλŠ”μ§€ ν™•μΈν•©λ‹ˆλ‹€.
    • importλ˜μ—ˆλ‹€λ©΄ ν•΄λ‹Ή 객체λ₯Ό λ°˜ν™˜ν•˜κ³  μ•ˆλ˜μ—ˆλ‹€λ©΄ importλ₯Ό instanceν™” ν•©λ‹ˆλ‹€.
    • λͺ¨λ“ˆμ€ import와 λ™μ‹œμ— μ΄ˆκΈ°ν™”λ˜μ§€λ§Œ, 같은 λͺ¨λ“ˆμ„ λ‹€μ‹œ importν•˜λ©΄ μ΄ˆκΈ°ν™”λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
    • κ·Έλž˜μ„œ, ν•œ 개의 객체만 μœ μ§€ν•˜κ³  λ°˜ν™˜ν•˜λŠ” Singleton λ°©μ‹μž…λ‹ˆλ‹€.