2. 디자인 패턴
디자인 패턴은 특정 문제를 해결하는 데에 있어 재사용 가능한 해결책입니다. 이는 코드의 효율성, 이해성, 유지 보수성을 향상할 수 있습니다.
2.1. 싱글턴 패턴
2.1.1. 싱글턴 패턴 개념
2.1.1.1. 싱글턴 패턴의 정의
싱글턴 패턴은 클래스의 인스턴스가 단 하나만 존재하도록 보장하는 디자인 패턴입니다. 이 패턴은 전역 변수를 사용하는 것과 유사한 효과를 가지지만, 전역 변수의 문제점을 피할 수 있습니다.
2.1.1.2. 싱글턴 패턴의 사용 사례
데이터베이스 연결, 로거, 파일 시스템, 윈도우 매니저 등의 리소스를 공유해야 하는 경우에 종종 사용됩니다.
2.1.2. 싱글턴 패턴 구현 및 활용
2.1.2.1. 파이썬에서 싱글턴 패턴 구현하기
파이썬에서 싱글턴 패턴을 구현하는 가장 간단한 방법은 모듈을 사용하는 것입니다. 모듈은 한 번만 로드되므로, 모듈 수준에서 객체를 생성하면 해당 객체는 싱글턴처럼 동작합니다.
그러나 클래스를 사용하여 싱글턴 패턴을 구현해야 하는 경우도 있습니다. 이를 위해 __new__ 메서드를 오버라이드하여 인스턴스 생성을 제어할 수 있습니다.
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance
2.1.2.2. 싱글턴 패턴 활용 예제
데이터베이스 연결 객체를 싱글턴으로 만드는 예제를 생각해봅시다. 데이터베이스 연결은 리소스를 많이 사용하므로, 동일한 연결을 공유하는 것이 효율적입니다.
class DatabaseConnection:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance
def __init__(self, database_uri):
self.database_uri = database_uri
# Assume that connecting to the database is a heavy operation
self.conn = self.connect_to_database()
def connect_to_database(self):
print(f"Connecting to database on {self.database_uri}")
return "database connection"
# Use the DatabaseConnection
db1 = DatabaseConnection("localhost:5432")
print(db1.conn) # "database connection"
db2 = DatabaseConnection("localhost:5433")
print(db2.conn) # "database connection"
# Despite the different parameters, db1 and db2 are the same object
print(db1 is db2) # True
이렇게 싱글턴 패턴을 사용하면, 여러 곳에서 동일한 리소스를 공유하는 경우에 유용합니다.
2.2. 팩토리 패턴
2.2.1. 팩토리 패턴 개념
2.2.1.1. 팩토리 패턴의 정의
팩토리 패턴은 객체 생성 로직을 캡슐화하는 디자인 패턴입니다. 이 패턴을 사용하면 클라이언트는 생성해야 할 객체의 정확한 클래스를 알 필요 없이, 팩토리 메서드를 통해 객체를 생성할 수 있습니다.
2.2.1.2. 팩토리 패턴의 사용 사례
팩토리 패턴은 객체를 생성하는 로직이 복잡하거나, 생성해야 하는 객체의 타입이 실행 시간에 결정되는 경우에 유용합니다.
2.2.2. 팩토리 패턴 구현 및 활용
2.2.2.1. 파이썬에서 팩토리 패턴 구현하기
팩토리 패턴을 구현하는 방법은 여러 가지가 있지만, 여기서는 간단한 팩토리 함수를 사용하는 방법을 보여드리겠습니다.
class Dog:
def __init__(self, name):
self.name = name
def speak(self):
return "Woof!"
class Cat:
def __init__(self, name):
self.name = name
def speak(self):
return "Meow!"
def get_pet(pet="dog"):
pets = dict(dog=Dog("Hope"), cat=Cat("Peace"))
return pets[pet]
2.2.2.2. 팩토리 패턴 활용 예제
팩토리 패턴을 사용하여 동물 객체를 생성하는 예제를 살펴봅시다.
dog = get_pet("dog")
print(dog.speak()) # "Woof!"
cat = get_pet("cat")
print(cat.speak()) # "Meow!"
이렇게 팩토리 패턴을 사용하면, 객체 생성 로직을 캡슐화하여 코드의 유연성을 높일 수 있습니다.
2.3. 옵저버 패턴
2.3.1. 옵저버 패턴 개념
2.3.1.1. 옵저버 패턴의 정의
옵저버 패턴은 한 개의 객체(주체)의 상태가 변경되면 그것을 감시하고 있는 다른 객체들(옵저버)에게 자동으로 알려주는 디자인 패턴입니다. 이 패턴은 주로 이벤트 핸들링 시스템에서 사용됩니다.
2.3.1.2. 옵저버 패턴의 사용 사례
GUI에서 사용자 입력을 모니터링하거나, 애플리케이션에서 이메일 알림을 보내는 등의 상황에서 유용합니다.
2.3.2. 옵저버 패턴 구현 및 활용
2.3.2.1. 파이썬에서 옵저버 패턴 구현하기
파이썬에서 옵저버 패턴을 구현하는 방법은 여러 가지가 있지만, 여기서는 간단한 방법을 사용하여 구현하겠습니다.
class Subject:
def __init__(self):
self._observers = []
def register(self, observer):
self._observers.append(observer)
def notify(self, message):
for observer in self._observers:
observer.notify(message)
class Observer:
def __init__(self, name):
self.name = name
def notify(self, message):
print(f"{self.name} received the message: {message}")
2.3.2.2. 옵저버 패턴 활용 예제
옵저버 패턴을 사용하여 메시지를 수신하는 객체를 만드는 예제를 살펴봅시다.
subject = Subject()
observer1 = Observer("Observer 1")
observer2 = Observer("Observer 2")
subject.register(observer1)
subject.register(observer2)
subject.notify("Hello, observers!")
이렇게 옵저버 패턴을 사용하면, 객체 간의 결합도를 낮추고 코드의 유연성을 높일 수 있습니다.
2.4. 데코레이터 패턴
2.4.1. 데코레이터 패턴 개념
2.4.1.1. 데코레이터 패턴의 정의
데코레이터 패턴은 기존 객체를 변경하지 않고 그 기능을 확장하거나 수정할 수 있게 하는 디자인 패턴입니다. 이 패턴은 기존 코드를 수정하지 않고도 객체의 행동을 동적으로 변경할 수 있습니다.
2.4.1.2. 데코레이터 패턴의 사용 사례
로그를 추가하거나, 사용자 권한을 확인하거나, 입력 값을 검증하는 등의 기능을 객체에 추가할 때 유용합니다.
2.4.2. 데코레이터 패턴 구현 및 활용
2.4.2.1. 파이썬에서 데코레이터 패턴 구현하기
파이썬에서는 데코레이터 패턴을 간단하게 구현할 수 있는 구문이 내장되어 있습니다. 파이썬의 데코레이터는 하나의 함수를 가져와 그 기능을 확장한 새로운 함수를 반환하는 함수입니다.
def decorator_function(original_function):
def wrapper_function(*args, **kwargs):
print(f"{original_function.__name__} 함수가 호출되기 전입니다.")
result = original_function(*args, **kwargs)
print(f"{original_function.__name__} 함수가 호출된 후입니다.")
return result
return wrapper_function
2.4.2.2. 데코레이터 패턴 활용 예제
데코레이터 패턴을 사용하여 함수 호출 전후로 로그를 출력하는 예제를 살펴봅시다.
@decorator_function
def display_info(name, age):
print(f"함수 display_info가 실행되었습니다. 인자: {name}, {age}")
display_info("John", 25)
이렇게 데코레이터 패턴을 사용하면, 기존 함수나 메서드의 기능을 수정하지 않고도 추가 기능을 쉽게 구현할 수 있습니다. 이는 코드의 재사용성과 유연성을 높입니다.
2023.05.12 - [GD's IT Lectures : 기초부터 시리즈/파이썬(Python) 기초부터 ~] - [파이썬(PYTHON) : 고급] 메타프로그래밍
'GD's IT Lectures : 기초부터 시리즈 > 파이썬(Python) 기초부터 ~' 카테고리의 다른 글
[파이썬(PYTHON) : 고급] 데이터베이스 연동 (2) | 2023.05.13 |
---|---|
[파이썬(PYTHON) : 고급] 성능 최적화 (0) | 2023.05.13 |
[파이썬(PYTHON) : 고급] 메타프로그래밍 (0) | 2023.05.12 |
[파이썬(PYTHON) : 중급] 동시성과 병렬성 (0) | 2023.05.11 |
[파이썬(PYTHON) : 중급] 네트워크 프로그래밍 (계속) (1) | 2023.05.11 |
댓글