Creation Design Pattern
글로벌하게 접근 가능한 단 한 개의 객체만을 허용하는 패턴
싱글턴은 클래스에 인스턴스가 하나만 있도록 하면서
이 인스턴스에 대한 전역 접근(액세스) 지점을 제공하는 생성 디자인 패턴
- 클래스에 대한 단일 객체 생성
- 전역 객체 제공
- 공유된 리소스에 대한 동시 접근 제어
- 글로벌 액세스 지점을 제공하는, 단점이 거의 없는 검증된 패턴
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() # create
print(s1)
s2 = Singleton() # recycle
print(s1)
print(s1 is s2) # True
def __new__(cls):
if not hasattr(cls, "instance"):
print("create")
cls.instance = super(Singleton, cls).__new__(cls)
else:
print("recycle")
return cls.instance
class LazyInstantiation:
_instance = None
def __init__(self):
if not LazyInstantiation._instance:
print("__init__ method called but nothing is created")
else:
print("instance already created: ", self.getInstance())
@classmethod
def getInstance(cls):
if not cls._instance:
cls._instance = LazyInstantiation()
return cls._instance
s = LazyInstantiation() # 클래스를 초기화하여도 객체 생성 x
print(s._instance)
s1 = LazyInstantiation.getInstance() # 객체 생성
s2 = LazyInstantiation()
- Metaclass를 간단히 설명하면, 클래스를 만드는 클래스라고 할 수 있음
- type은 객체의 클래스 종류를 알아낼 때 사용되지만, 클래스를 만들어낼 수도 있음
- type을 상속받게 되면 메타클래스가 되며, 주로 클래스 동작을 제어할 때 사용됨
- 메타클래스는 call 함수를 통항 객체 생성에 관한 제어를 할 수 있음
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)
class int(metaclass=MyInt):를 통해 메타클래스를 지정함
생성시 MyInt의 call이 호출
- *args = 인자를 typle로 만들어줌
- **kwds = 딕셔너리로 만들어서 내부로 전달함
class MetaSingleton(type):
_instance = {}
def __call__(cls, *args, **kwds):
if cls not in cls._instance:
cls._instance[cls] = super(MetaSingleton, cls).__call__(*args, **kwds)
return cls._instance[cls]
class Box(metaclass = MetaSingleton):
pass
b1 = Box() # create
b2 = Box() # recycle
print(b1==b2) # True
- MetaSingleton(type)으로 type을 상속받게 되어 메타클래스가 됨
- 생성자를 private으로 선언하는데 _instance 생성
- call을 통해 생성여부 판단, 없으면 생성해서 리턴
- Box 클래스(메타클래스)를 싱글톤으로 지정
- 이러면 Box 클래스는 단 하나만 만들 수 있어짐, 싱글톤으로 지정되었기 때문
- 그래서 print(b1==b2)를 하면 True가 출력됨
- 단일 책임 원칙(SRP)을 위반
- 전역 변수의 값이 실수로 변경된 것을 모르고 사용될 수 있음
- 같은 객체에 대한 여러 참조자가 생김
- 전역 변수를 수정할 시 의도치 않게 다른 클래스에도 영향을 줄 수 있음