ν΅μ¬ νμ΄μ¬ λμμΈ ν¨ν΄μ λ§μ€ν°νμΈμ. μ΄ μ¬μΈ΅ κ°μ΄λλ μ±κΈν€, ν©ν 리, μ΅μ λ² ν¨ν΄μ ꡬν, μ¬μ© μ¬λ‘, λͺ¨λ² μ¬λ‘λ₯Ό μ€μ©μ μΈ μ½λ μμ μ ν¨κ» λ€λ£Ήλλ€.
κ°λ°μλ₯Ό μν νμ΄μ¬ λμμΈ ν¨ν΄ κ°μ΄λ: μ±κΈν€, ν©ν 리, μ΅μ λ²
μννΈμ¨μ΄ μμ§λμ΄λ§μ μΈκ³μμ λ¨μν μλνλ μ½λλ₯Ό μμ±νλ κ²μ 첫걸μμ λΆκ³Όν©λλ€. νμ₯ κ°λ₯νκ³ , μ μ§λ³΄μ κ°λ₯νλ©°, μ μ°ν μννΈμ¨μ΄λ₯Ό λ§λλ κ²μ΄ μ λ¬Έ κ°λ°μμ νΉμ§μ λλ€. λ°λ‘ μ΄ μ§μ μμ λμμΈ ν¨ν΄μ΄ λ±μ₯ν©λλ€. λμμΈ ν¨ν΄μ νΉμ μκ³ λ¦¬μ¦μ΄λ λΌμ΄λΈλ¬λ¦¬κ° μλλΌ, μννΈμ¨μ΄ μ€κ³μμ νν λ°μνλ λ¬Έμ λ€μ ν΄κ²°νκΈ° μν μμ μμ€μ, μΈμ΄μ ꡬμ λ°μ§ μλ μ²μ¬μ§μ λλ€.
μ΄ μ’ ν© κ°μ΄λμμλ νμ΄μ¬μΌλ‘ ꡬνλ κ°μ₯ κΈ°λ³Έμ μ΄κ³ λ리 μ¬μ©λλ μΈ κ°μ§ λμμΈ ν¨ν΄μΈ μ±κΈν€(Singleton), ν©ν 리(Factory), μ΅μ λ²(Observer)μ λν΄ κΉμ΄ νꡬν©λλ€. μ΄λ€μ΄ 무μμΈμ§, μ μ μ©νμ§, κ·Έλ¦¬κ³ νμ΄μ¬ νλ‘μ νΈμμ ν¨κ³Όμ μΌλ‘ ꡬννλ λ°©λ²μ μ΄ν΄λ³΄κ² μ΅λλ€.
λμμΈ ν¨ν΄μ΄λ 무μμ΄λ©° μ μ€μνκ°?
"GoF(Gang of Four)"κ° κ·Έλ€μ κΈ°λ λΉμ μΈ μ μ "λμμΈ ν¨ν΄: μ¬μ¬μ© κ°λ₯ν κ°μ²΄ μ§ν₯ μννΈμ¨μ΄μ μμ(Design Patterns: Elements of Reusable Object-Oriented Software)"μμ μ²μ κ°λ νν λμμΈ ν¨ν΄μ λ°λ³΅μ μΌλ‘ λ°μνλ μ€κ³ λ¬Έμ μ λν κ²μ¦λ ν΄κ²°μ± μ λλ€. μ΄ ν¨ν΄λ€μ κ°λ°μλ€μκ² κ³΅μ λ μ΄νλ₯Ό μ 곡νμ¬, νμ΄ λ³΅μ‘ν μν€ν μ² μ루μ μ λ ν¨μ¨μ μΌλ‘ λ Όμν μ μκ² ν©λλ€.
λμμΈ ν¨ν΄μ μ¬μ©νλ©΄ λ€μκ³Ό κ°μ μ΄μ μ΄ μμ΅λλ€:
- μ¬μ¬μ©μ± μ¦κ°: μ μ€κ³λ μ»΄ν¬λνΈλ μ¬λ¬ λ€λ₯Έ νλ‘μ νΈμμ μ¬μ¬μ©λ μ μμ΅λλ€.
- μ μ§λ³΄μμ± ν₯μ: μ½λκ° λ 체κ³νλκ³ μ΄ν΄νκΈ° μ¬μμ§λ©°, λ³κ²½μ΄ νμν λ λ²κ·Έκ° λ°μν κ°λ₯μ±μ΄ μ€μ΄λλλ€.
- νμ₯μ± κ°ν: μν€ν μ²κ° λ μ μ°ν΄μ Έμ μ 체λ₯Ό λ€μ μμ±ν νμ μμ΄ μμ€ν μ΄ μ±μ₯ν μ μμ΅λλ€.
- λμ¨ν κ²°ν©: μ»΄ν¬λνΈλ€μ΄ μλ‘ λ μμ‘΄νκ² λμ΄ λͺ¨λμ±κ³Ό λ 립μ μΈ κ°λ°μ μ΄μ§ν©λλ€.
μ΄μ κ°μ²΄ μμ±μ μ μ΄νλ μμ± ν¨ν΄μΈ μ±κΈν€λΆν° ννμ μμνκ² μ΅λλ€.
μ±κΈν€ ν¨ν΄: λͺ¨λ κ²μ μ§λ°°νλ λ¨ νλμ μΈμ€ν΄μ€
μ±κΈν€ ν¨ν΄μ΄λ?
μ±κΈν€ ν¨ν΄μ ν΄λμ€κ° λ¨ νλμ μΈμ€ν΄μ€λ§ κ°λλ‘ λ³΄μ₯νκ³ μ΄μ λν λ¨μΌνκ³ μ μμ μΈ μ κ·Ό μ§μ μ μ 곡νλ μμ± ν¨ν΄μ λλ€. μμ€ν μ λ°μ κ΅¬μ± κ΄λ¦¬μ, λ‘κΉ μλΉμ€, λλ λ°μ΄ν°λ² μ΄μ€ μ°κ²° νμ μκ°ν΄λ³΄μΈμ. μ΄λ° μ»΄ν¬λνΈλ€μ λ 립μ μΈ μ¬λ¬ μΈμ€ν΄μ€κ° λ λ€λλ κ²μ μμΉ μμ κ²μ λλ€. λ¨μΌνκ³ κΆμ μλ μμ€κ° νμν©λλ€.
μ±κΈν€μ ν΅μ¬ μμΉμ λ€μκ³Ό κ°μ΅λλ€:
- λ¨μΌ μΈμ€ν΄μ€: ν΄λμ€λ μ ν리μΌμ΄μ μλͺ μ£ΌκΈ° λμ λ¨ ν λ²λ§ μΈμ€ν΄μ€νλ μ μμ΅λλ€.
- μ μμ μ κ·Ό: μ½λλ² μ΄μ€ μ΄λμμλ μ΄ μ μΌν μΈμ€ν΄μ€μ μ κ·Όν μ μλ λ©μ»€λμ¦μ΄ μ‘΄μ¬ν©λλ€.
μΈμ μ¬μ©νκ³ μΈμ νΌν΄μΌ νλκ°
μ±κΈν€ ν¨ν΄μ κ°λ ₯νμ§λ§ μ’ μ’ λ¨μ©λ©λλ€. μ μ ν μ¬μ© μ¬λ‘μ κ·Έμ λ°λ₯΄λ μ€λν λ¨μ μ μ΄ν΄νλ κ²μ΄ μ€μν©λλ€.
μ’μ μ¬μ© μ¬λ‘:
- λ‘κΉ : λ¨μΌ λ‘κΉ κ°μ²΄λ λ‘κ·Έ κ΄λ¦¬λ₯Ό μ€μ μ§μ€ννμ¬ μ ν리μΌμ΄μ μ λͺ¨λ λΆλΆμ΄ λμΌν νμΌμ΄λ μλΉμ€μ μ‘°νλ‘κ² λ‘κ·Έλ₯Ό κΈ°λ‘νλλ‘ λ³΄μ₯ν μ μμ΅λλ€.
- κ΅¬μ± κ΄λ¦¬: μ ν리μΌμ΄μ μ κ΅¬μ± μ€μ (μ: API ν€, κΈ°λ₯ νλκ·Έ)μ ν λ²λ§ λ‘λλμ΄μΌ νλ©°, λ¨μΌ μ§μ€ 곡κΈμ(source of truth)μμ μ μμ μΌλ‘ μ κ·Όλμ΄μΌ ν©λλ€.
- λ°μ΄ν°λ² μ΄μ€ μ°κ²° ν: λ°μ΄ν°λ² μ΄μ€ μ°κ²° νμ κ΄λ¦¬νλ κ²μ 리μμ€ μλͺ¨κ° ν° μμ μ λλ€. μ±κΈν€μ νμ΄ ν λ²λ§ μμ±λκ³ μ ν리μΌμ΄μ μ 체μμ ν¨μ¨μ μΌλ‘ 곡μ λλλ‘ λ³΄μ₯ν μ μμ΅λλ€.
- νλμ¨μ΄ μΈν°νμ΄μ€ μ κ·Ό: νλ¦°ν°λ νΉμ μΌμμ κ°μ λ¨μΌ νλμ¨μ΄μ μΈν°νμ΄μ€ν λ, μ±κΈν€μ μ¬λ¬ λμ μ κ·Ό μλλ‘ μΈν μΆ©λμ λ°©μ§ν μ μμ΅λλ€.
μ±κΈν€μ μνμ± (μν°ν¨ν΄ κ΄μ ):
μ μ©μ±μλ λΆκ΅¬νκ³ μ±κΈν€μ μ’ μ’ μν°ν¨ν΄μΌλ‘ κ°μ£Όλ©λλ€. κ·Έ μ΄μ λ λ€μκ³Ό κ°μ΅λλ€:
- λ¨μΌ μ± μ μμΉ μλ°: μ±κΈν€ ν΄λμ€λ ν΅μ¬ λ‘μ§κ³Ό μ체 μλͺ μ£ΌκΈ° κ΄λ¦¬(λ¨μΌ μΈμ€ν΄μ€ 보μ₯)λΌλ λ κ°μ§ μ± μμ κ°μ§λλ€.
- μ μ μν λμ : μ μ μνλ μ½λλ₯Ό μΆλ‘ νκ³ λλ²κΉ νκΈ° μ΄λ ΅κ² λ§λλλ€. μμ€ν μ ν λΆλΆμμμ λ³κ²½μ΄ λ€λ₯Έ λΆλΆμμ μκΈ°μΉ μμ λΆμμ©μ μΌμΌν¬ μ μμ΅λλ€.
- ν μ€νΈ μ©μ΄μ± μ ν΄: μ μ μ±κΈν€μ μμ‘΄νλ μ»΄ν¬λνΈλ€μ κ·Έκ²κ³Ό κ°νκ² κ²°ν©λ©λλ€. μ΄λ λ¨μ ν μ€νΈλ₯Ό μ΄λ ΅κ² λ§λλλ°, 격리λ ν μ€νΈλ₯Ό μν΄ μ±κΈν€μ λͺ¨μ(mock) κ°μ²΄λ μ€ν (stub)μΌλ‘ μ½κ² κ΅μ²΄ν μ μκΈ° λλ¬Έμ λλ€.
μ λ¬Έκ° ν: μ±κΈν€μ μ¬μ©νκΈ° μ μ μμ‘΄μ± μ£Όμ (Dependency Injection)μ΄ λ¬Έμ λ₯Ό λ μ°μνκ² ν΄κ²°ν μ μλμ§ κ³ λ €ν΄λ³΄μΈμ. (μ€μ κ°μ²΄μ κ°μ) κ°μ²΄μ λ¨μΌ μΈμ€ν΄μ€λ₯Ό νμν ν΄λμ€μ μ λ¬νλ©΄ μ μ μνμ ν¨μ μμ΄ λμΌν λͺ©νλ₯Ό λ¬μ±ν μ μμ΅λλ€.
νμ΄μ¬μμ μ±κΈν€ ꡬννκΈ°
νμ΄μ¬μ μ±κΈν€ ν¨ν΄μ ꡬννλ μ¬λ¬ λ°©λ²μ μ 곡νλ©°, κ°κ° μ₯λ¨μ μ΄ μμ΅λλ€. νμ΄μ¬μ ν₯λ―Έλ‘μ΄ μ μ€ νλλ λͺ¨λ μμ€ν μ΄ λ³Έμ§μ μΌλ‘ μ±κΈν€μ²λΌ λμνλ€λ κ²μ λλ€. λͺ¨λμ μν¬νΈνλ©΄ νμ΄μ¬μ λͺ¨λμ ν λ²λ§ λ‘λνκ³ μ΄κΈ°νν©λλ€. μ½λμ λ€λ₯Έ λΆλΆμμ λμΌν λͺ¨λμ λ€μ μν¬νΈνλ©΄ λμΌν λͺ¨λ κ°μ²΄μ λν μ°Έμ‘°κ° λ°νλ©λλ€.
μ΄μ λ λͺ μμ μΈ ν΄λμ€ κΈ°λ° κ΅¬νμ μ΄ν΄λ³΄κ² μ΅λλ€.
ꡬν 1: λ©νν΄λμ€ μ¬μ©
λ©νν΄λμ€λ₯Ό μ¬μ©νλ κ²μ μ’ μ’ μ±κΈν€μ ꡬννλ κ°μ₯ κ²¬κ³ νκ³ "νμ΄μ¬μ€λ¬μ΄" λ°©λ²μΌλ‘ κ°μ£Όλ©λλ€. ν΄λμ€κ° κ°μ²΄μ λμμ μ μνλ―μ΄, λ©νν΄λμ€λ ν΄λμ€μ λμμ μ μν©λλ€. μ΄λ₯Ό ν΅ν΄ ν΄λμ€ μμ± κ³Όμ μ κ°λ‘μ± μ μμ΅λλ€.
class SingletonMeta(type):
"""A metaclass for creating a Singleton class."""
_instances = {}
def __call__(cls, *args, **kwargs):
# This method is called when an instance is created, e.g., MyClass()
if cls not in cls._instances:
instance = super().__call__(*args, **kwargs)
cls._instances[cls] = instance
return cls._instances[cls]
class GlobalConfig(metaclass=SingletonMeta):
def __init__(self):
# This will only be executed the first time the instance is created.
print("Initializing GlobalConfig...")
self.settings = {"api_key": "default_key", "timeout": 30}
def get_setting(self, key):
return self.settings.get(key)
# --- Usage ---
config1 = GlobalConfig()
config2 = GlobalConfig()
print(f"config1 settings: {config1.settings}")
config1.settings["api_key"] = "new_secret_key_12345"
print(f"config2 settings: {config2.settings}") # Will show the updated key
# Verify they are the same object
print(f"Are config1 and config2 the same instance? {config1 is config2}")
μ΄ μμ μμ `SingletonMeta`μ `__call__` λ©μλλ `GlobalConfig`μ μΈμ€ν΄μ€νλ₯Ό κ°λ‘μ±λλ€. `_instances` λμ λ리λ₯Ό μ μ§νλ©° `GlobalConfig`μ μΈμ€ν΄μ€κ° λ¨ νλλ§ μμ±λκ³ μ μ₯λλλ‘ λ³΄μ₯ν©λλ€.
ꡬν 2: λ°μ½λ μ΄ν° μ¬μ©
λ°μ½λ μ΄ν°λ ν΄λμ€μ λ΄λΆ ꡬ쑰λ₯Ό λ³κ²½νμ§ μκ³ μ±κΈν€ λμμ μΆκ°νλ λ κ°κ²°νκ³ κ°λ μ± μ’μ λ°©λ²μ μ 곡ν©λλ€.
def singleton(cls):
"""A decorator to turn a class into a Singleton."""
instances = {}
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class DatabaseConnection:
def __init__(self):
print("Connecting to the database...")
# Simulate a database connection setup
self.connection_id = id(self)
# --- Usage ---
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(f"DB1 Connection ID: {db1.connection_id}")
print(f"DB2 Connection ID: {db2.connection_id}")
print(f"Are db1 and db2 the same instance? {db1 is db2}")
μ΄ μ κ·Ό λ°©μμ κΉλνλ©° μ±κΈν€ λ‘μ§μ ν΄λμ€ μ체μ λΉμ¦λμ€ λ‘μ§κ³Ό λΆλ¦¬ν©λλ€. νμ§λ§ μμμ΄λ μΈνΈλ‘μ€νμ κ³Ό κ΄λ ¨νμ¬ λ―Έλ¬ν λ¬Έμ κ° μμ μ μμ΅λλ€.
ν©ν 리 ν¨ν΄: κ°μ²΄ μμ±μ λΆλ¦¬
λ€μμΌλ‘, λ λ€λ₯Έ κ°λ ₯ν μμ± ν¨ν΄μΈ ν©ν λ¦¬λ‘ λμ΄κ°κ² μ΅λλ€. ν©ν 리 ν¨ν΄μ ν΅μ¬ μμ΄λμ΄λ κ°μ²΄ μμ± κ³Όμ μ μΆμννλ κ²μ λλ€. μμ±μ(μ: `my_obj = MyClass()`)λ₯Ό μ¬μ©νμ¬ μ§μ κ°μ²΄λ₯Ό μμ±νλ λμ , ν©ν 리 λ©μλλ₯Ό νΈμΆν©λλ€. μ΄λ ν΄λΌμ΄μΈνΈ μ½λλ₯Ό μΈμ€ν΄μ€νν΄μΌ νλ ꡬ체μ μΈ ν΄λμ€λ‘λΆν° λΆλ¦¬(decouple)ν©λλ€.
μ΄λ¬ν λΆλ¦¬λ λ§€μ° κ°μΉκ° μμ΅λλ€. μ¬λ¬λΆμ μ ν리μΌμ΄μ μ΄ PDF, CSV, JSONκ³Ό κ°μ λ€μν νμμΌλ‘ λ°μ΄ν°λ₯Ό λ΄λ³΄λ΄λ κΈ°λ₯μ μ§μνλ€κ³ μμν΄λ³΄μΈμ. ν©ν λ¦¬κ° μλ€λ©΄ ν΄λΌμ΄μΈνΈ μ½λλ λ€μκ³Ό κ°μ μ μμ΅λλ€:
if export_format == 'pdf':
exporter = PDFExporter()
elif export_format == 'csv':
exporter = CSVExporter()
else:
exporter = JSONExporter()
exporter.export(data)
μ΄ μ½λλ κΉ¨μ§κΈ° μ½μ΅λλ€. μλ‘μ΄ νμ(μ: XML)μ μΆκ°νλ©΄, μ΄ λ‘μ§μ΄ μλ λͺ¨λ κ³³μ μ°Ύμ μμ ν΄μΌ ν©λλ€. ν©ν 리λ μ΄ μμ± λ‘μ§μ μ€μμμ κ΄λ¦¬ν©λλ€.
ν©ν 리 λ©μλ ν¨ν΄
ν©ν 리 λ©μλ ν¨ν΄μ κ°μ²΄ μμ±μ μν μΈν°νμ΄μ€λ₯Ό μ μνμ§λ§, μ΄λ€ ν΄λμ€μ μΈμ€ν΄μ€λ₯Ό μμ±ν μ§λ μλΈν΄λμ€κ° κ²°μ νλλ‘ ν©λλ€. μ¦, μΈμ€ν΄μ€νλ₯Ό μλΈν΄λμ€μ 미루λ κ²μ λλ€.
ꡬ쑰:
- μ ν(Product): ν©ν 리 λ©μλκ° μμ±νλ κ°μ²΄μ λν μΈν°νμ΄μ€μ λλ€ (μ: `Document`).
- ꡬ체μ μΈ μ ν(ConcreteProduct): μ ν μΈν°νμ΄μ€μ ꡬ체μ μΈ κ΅¬ν체μ λλ€ (μ: `PDFDocument`, `WordDocument`).
- μμ±μ(Creator): ν©ν 리 λ©μλ(`create_document()`)λ₯Ό μ μΈνλ μΆμ ν΄λμ€μ λλ€. ν©ν 리 λ©μλλ₯Ό μ¬μ©νλ ν νλ¦Ώ λ©μλλ₯Ό μ μν μλ μμ΅λλ€.
- ꡬ체μ μΈ μμ±μ(ConcreteCreator): νΉμ ꡬ체μ μΈ μ νμ μΈμ€ν΄μ€λ₯Ό λ°ννλλ‘ ν©ν 리 λ©μλλ₯Ό μ€λ²λΌμ΄λνλ μλΈν΄λμ€μ λλ€ (μ: `PDFCreator`λ `PDFDocument`λ₯Ό λ°ν).
μ€μ© μμ : ν¬λ‘μ€ νλ«νΌ UI ν΄ν·
μλ‘ λ€λ₯Έ μ΄μ 체μ μ λ§λ λ€λ₯Έ λ²νΌμ μμ±ν΄μΌ νλ UI νλ μμν¬λ₯Ό ꡬμΆνκ³ μλ€κ³ μμν΄ λ΄ μλ€.
from abc import ABC, abstractmethod
# --- Product Interface and Concrete Products ---
class Button(ABC):
"""Product Interface: Defines the interface for buttons."""
@abstractmethod
def render(self):
pass
class WindowsButton(Button):
"""Concrete Product: A button with Windows OS style."""
def render(self):
print("Rendering a button in Windows style.")
class MacOSButton(Button):
"""Concrete Product: A button with macOS style."""
def render(self):
print("Rendering a button in macOS style.")
# --- Creator (Abstract) and Concrete Creators ---
class Dialog(ABC):
"""Creator: Declares the factory method.
It also contains business logic that uses the product.
"""
@abstractmethod
def create_button(self) -> Button:
"""The factory method."""
pass
def show_dialog(self):
"""The core business logic that isn't aware of concrete button types."""
print("Showing a generic dialog box.")
button = self.create_button()
button.render()
class WindowsDialog(Dialog):
"""Concrete Creator for Windows."""
def create_button(self) -> Button:
return WindowsButton()
class MacOSDialog(Dialog):
"""Concrete Creator for macOS."""
def create_button(self) -> Button:
return MacOSButton()
# --- Client Code ---
def initialize_app(os_name: str):
if os_name == "Windows":
dialog = WindowsDialog()
elif os_name == "macOS":
dialog = MacOSDialog()
else:
raise ValueError(f"Unsupported OS: {os_name}")
dialog.show_dialog()
# Simulate running the app on different OS
print("--- Running on Windows ---")
initialize_app("Windows")
print("\n--- Running on macOS ---")
initialize_app("macOS")
`show_dialog` λ©μλκ° κ΅¬μ²΄μ μΈ `Button` μ νμ μμ§ λͺ»ν μ± μ΄λ€ `Button`κ³Όλ μλνλ λ°©μμ μ£Όλͺ©νμΈμ. μ΄λ€ λ²νΌμ λ§λ€μ§ κ²°μ νλ κ²μ `WindowsDialog`μ `MacOSDialog` μλΈν΄λμ€μ μμλ©λλ€. μ΄λ‘ μΈν΄ `Dialog` ν΄λμ€λ μ΄λ₯Ό μ¬μ©νλ ν΄λΌμ΄μΈνΈ μ½λλ₯Ό λ³κ²½νμ§ μκ³ λ `LinuxDialog`λ₯Ό μΆκ°νλ κ²μ΄ λ§€μ° κ°λ¨ν΄μ§λλ€.
μΆμ ν©ν 리 ν¨ν΄
μΆμ ν©ν 리 ν¨ν΄μ μ΄λ₯Ό ν λ¨κ³ λ λ°μ μν΅λλ€. μ΄ ν¨ν΄μ ꡬ체μ μΈ ν΄λμ€λ₯Ό μ§μ νμ§ μκ³ κ΄λ ¨λκ±°λ μμ‘΄μ μΈ κ°μ²΄λ€μ μ§ν©(family)μ μμ±νκΈ° μν μΈν°νμ΄μ€λ₯Ό μ 곡ν©λλ€. μ΄λ λ€λ₯Έ ν©ν 리λ₯Ό μμ±νκΈ° μν ν©ν 리μ κ°μ΅λλ€.
UI μμ λ₯Ό κ³μ μ΄ν΄λ³΄λ©΄, λν μμμλ λ²νΌλ§ μλ κ²μ΄ μλλΌ μ²΄ν¬λ°μ€, ν μ€νΈ νλ λ±λ μμ΅λλ€. μΌκ΄λ λͺ¨μκ³Ό λλ(ν λ§)μ μ μ§νλ €λ©΄ μ΄λ¬ν λͺ¨λ μμκ° λμΌν μ§ν©μ μν΄μΌ ν©λλ€(μ: λͺ¨λ Windows μ€νμΌ λλ λͺ¨λ macOS μ€νμΌ).
ꡬ쑰:
- μΆμ ν©ν 리(AbstractFactory): μΆμ μ νμ μμ±νκΈ° μν ν©ν 리 λ©μλ μ§ν©μ΄ μλ μΈν°νμ΄μ€μ λλ€ (μ: `create_button()`, `create_checkbox()`).
- ꡬ체μ μΈ ν©ν 리(ConcreteFactory): μΆμ ν©ν 리λ₯Ό ꡬννμ¬ κ΅¬μ²΄μ μΈ μ νκ΅°μ μμ±ν©λλ€ (μ: `LightThemeFactory`, `DarkThemeFactory`).
- μΆμ μ ν(AbstractProduct): μ νκ΅°μ μν κ° κ°λ³ μ νμ λν μΈν°νμ΄μ€μ λλ€ (μ: `Button`, `Checkbox`).
- ꡬ체μ μΈ μ ν(ConcreteProduct): κ° μ νκ΅°μ λν ꡬ체μ μΈ κ΅¬ν체μ λλ€ (μ: `LightButton`, `DarkButton`, `LightCheckbox`, `DarkCheckbox`).
μ€μ© μμ : UI ν λ§ ν©ν 리
from abc import ABC, abstractmethod
# --- Abstract Product Interfaces ---
class Button(ABC):
@abstractmethod
def paint(self):
pass
class Checkbox(ABC):
@abstractmethod
def paint(self):
pass
# --- Concrete Products for the 'Light' Theme ---
class LightButton(Button):
def paint(self):
print("Painting a light theme button.")
class LightCheckbox(Checkbox):
def paint(self):
print("Painting a light theme checkbox.")
# --- Concrete Products for the 'Dark' Theme ---
class DarkButton(Button):
def paint(self):
print("Painting a dark theme button.")
class DarkCheckbox(Checkbox):
def paint(self):
print("Painting a dark theme checkbox.")
# --- Abstract Factory Interface ---
class UIFactory(ABC):
@abstractmethod
def create_button(self) -> Button:
pass
@abstractmethod
def create_checkbox(self) -> Checkbox:
pass
# --- Concrete Factories for each theme ---
class LightThemeFactory(UIFactory):
def create_button(self) -> Button:
return LightButton()
def create_checkbox(self) -> Checkbox:
return LightCheckbox()
class DarkThemeFactory(UIFactory):
def create_button(self) -> Button:
return DarkButton()
def create_checkbox(self) -> Checkbox:
return DarkCheckbox()
# --- Client Code ---
class Application:
def __init__(self, factory: UIFactory):
self.factory = factory
self.button = None
self.checkbox = None
def create_ui(self):
self.button = self.factory.create_button()
self.checkbox = self.factory.create_checkbox()
def paint_ui(self):
self.button.paint()
self.checkbox.paint()
# --- Main application logic ---
def get_factory_for_theme(theme_name: str) -> UIFactory:
if theme_name == "light":
return LightThemeFactory()
elif theme_name == "dark":
return DarkThemeFactory()
else:
raise ValueError(f"Unknown theme: {theme_name}")
# Create and run the application with a specific theme
current_theme = "dark"
ui_factory = get_factory_for_theme(current_theme)
app = Application(ui_factory)
app.create_ui()
app.paint_ui()
`Application` ν΄λμ€λ ν λ§μ λν΄ μ ν μμ§ λͺ»ν©λλ€. λ¨μ§ UI μμλ₯Ό μ»κΈ° μν΄ `UIFactory`κ° νμνλ€λ κ²λ§ μκ³ μμ΅λλ€. `Application` ν΄λΌμ΄μΈνΈ μ½λλ₯Ό μ ν 건λλ¦¬μ§ μκ³ λ μλ‘μ΄ μ ν ν΄λμ€ μ§ν©κ³Ό μλ‘μ΄ ν©ν 리λ₯Ό λ§λ€μ΄ μμ ν μλ‘μ΄ ν λ§(μ: `HighContrastThemeFactory`)λ₯Ό λμ ν μ μμ΅λλ€.
μ΅μ λ² ν¨ν΄: κ°μ²΄λ€μκ² μ΅μ μ 보 μλ €μ£ΌκΈ°
λ§μ§λ§μΌλ‘, ν΅μ¬μ μΈ νμ ν¨ν΄μΈ μ΅μ λ²λ₯Ό μ΄ν΄λ³΄κ² μ΅λλ€. μ΄ ν¨ν΄μ κ°μ²΄ κ°μ μΌλλ€(one-to-many) μμ‘΄μ±μ μ μνμ¬, ν κ°μ²΄(주체, subject)μ μνκ° λ³νλ©΄ κ·Έμ μμ‘΄νλ λͺ¨λ κ°μ²΄(μ΅μ λ², observer)λ€μ΄ μλμΌλ‘ μλ¦Όμ λ°κ³ μ λ°μ΄νΈλλλ‘ ν©λλ€.
μ΄ ν¨ν΄μ μ΄λ²€νΈ κΈ°λ° νλ‘κ·Έλλ°μ κΈ°μ΄μ λλ€. λ΄μ€λ ν°λ₯Ό ꡬλ νκ±°λ, μμ λ―Έλμ΄μμ λκ΅°κ°λ₯Ό νλ‘μ°νκ±°λ, μ£Όκ° μλ¦Όμ λ°λ κ²μ μκ°ν΄λ³΄μΈμ. κ° κ²½μ°μ μ¬λ¬λΆ(μ΅μ λ²)μ 주체μ λν κ΄μ¬μ λ±λ‘νκ³ , μλ‘μ΄ μΌμ΄ λ°μνλ©΄ μλμΌλ‘ μλ¦Όμ λ°μ΅λλ€.
ν΅μ¬ κ΅¬μ± μμ: 주체μ μ΅μ λ²
- 주체(Subject λλ Observable): κ΄μ¬μ λμμ΄ λλ κ°μ²΄μ λλ€. μμ μ μ΅μ λ² λͺ©λ‘μ μ μ§νκ³ , μ΅μ λ²λ₯Ό λ±λ‘(`subscribe`), ν΄μ§(`unsubscribe`), μλ¦Ό(`notify`)νλ λ©μλλ₯Ό μ 곡ν©λλ€.
- μ΅μ λ²(Observer λλ Subscriber): λ³κ²½ μ¬νμ ν΅λ³΄λ°κ³ μΆμ΄νλ κ°μ²΄μ λλ€. 주체μ μνκ° λ³κ²½λ λ μ£Όμ²΄κ° νΈμΆνλ μ λ°μ΄νΈ μΈν°νμ΄μ€λ₯Ό μ μν©λλ€.
μΈμ μ¬μ©νλκ°
- μ΄λ²€νΈ μ²λ¦¬ μμ€ν : GUI ν΄ν·μ΄ λνμ μΈ μμ λλ€. λ²νΌ(주체)μ ν΄λ¦λ λ μ¬λ¬ 리μ€λ(μ΅μ λ²)μκ² μ립λλ€.
- μλ¦Ό μλΉμ€: λ΄μ€ μΉμ¬μ΄νΈ(주체)μ μ κΈ°μ¬κ° κ²μλλ©΄ λͺ¨λ λ±λ‘λ ꡬλ μ(μ΅μ λ²)κ° μ΄λ©μΌμ΄λ νΈμ μλ¦Όμ λ°μ΅λλ€.
- λͺ¨λΈ-λ·°-컨νΈλ‘€λ¬(MVC) μν€ν μ²: λͺ¨λΈ(주체)μ λ°μ΄ν° λ³κ²½μ΄ μμ λλ§λ€ λ·°(μ΅μ λ²)μκ² μλ €, λ·°κ° μ λ°μ΄νΈλ μ 보λ₯Ό νμνκΈ° μν΄ μμ μ λ€μ λ λλ§νλλ‘ ν©λλ€. μ΄λ λ°μ΄ν° λ‘μ§κ³Ό νλ μ ν μ΄μ λ‘μ§μ λΆλ¦¬ν΄ μ€λλ€.
- λͺ¨λν°λ§ μμ€ν : μμ€ν μν λͺ¨λν°(주체)λ μ€μν μ§ν(CPU μ¬μ©λμ΄λ λ©λͺ¨λ¦¬ λ±)κ° μκ³κ°μ λμ λ λ€μν λμ보λμ κ²½κ³ μμ€ν (μ΅μ λ²)μ μ릴 μ μμ΅λλ€.
νμ΄μ¬μμ μ΅μ λ² ν¨ν΄ ꡬννκΈ°
μ¬κΈ° λ΄μ€ μμ΄μ μκ° λ€μν μ νμ ꡬλ μμκ² μλ¦Όμ 보λ΄λ μ€μ©μ μΈ κ΅¬ν μμ κ° μμ΅λλ€.
from abc import ABC, abstractmethod
from typing import List
# --- Observer Interface and Concrete Observers ---
class Observer(ABC):
@abstractmethod
def update(self, subject):
pass
class EmailNotifier(Observer):
def __init__(self, email_address: str):
self.email_address = email_address
def update(self, subject):
print(f"Sending Email to {self.email_address}: New story available! Title: '{subject.latest_story}'")
class SMSNotifier(Observer):
def __init__(self, phone_number: str):
self.phone_number = phone_number
def update(self, subject):
print(f"Sending SMS to {self.phone_number}: News Alert: '{subject.latest_story}'")
# --- Subject (Observable) Class ---
class NewsAgency:
def __init__(self):
self._observers: List[Observer] = []
self._latest_story: str = ""
def attach(self, observer: Observer) -> None:
print("News Agency: Attached an observer.")
self._observers.append(observer)
def detach(self, observer: Observer) -> None:
print("News Agency: Detached an observer.")
self._observers.remove(observer)
def notify(self) -> None:
print("News Agency: Notifying observers...")
for observer in self._observers:
observer.update(self)
@property
def latest_story(self) -> str:
return self._latest_story
def add_new_story(self, story: str) -> None:
print(f"\nNews Agency: Publishing new story: '{story}'")
self._latest_story = story
self.notify()
# --- Client Code ---
# Create the subject
agency = NewsAgency()
# Create observers
email_subscriber1 = EmailNotifier("reader1@example.com")
sms_subscriber1 = SMSNotifier("+15551234567")
email_subscriber2 = EmailNotifier("another.reader@example.com")
# Attach observers to the subject
agency.attach(email_subscriber1)
agency.attach(sms_subscriber1)
agency.attach(email_subscriber2)
# The subject's state changes, and all observers are notified
agency.add_new_story("Global Tech Summit Begins Next Week")
# Detach an observer
agency.detach(email_subscriber1)
# Another state change occurs
agency.add_new_story("Breakthrough in Renewable Energy Announced")
μ΄ μμ μμ `NewsAgency`λ `EmailNotifier`λ `SMSNotifier`μ λν΄ μ무κ²λ μ νμκ° μμ΅λλ€. λ¨μ§ κ·Έλ€μ΄ `update` λ©μλλ₯Ό κ°μ§ `Observer` κ°μ²΄λΌλ κ²λ§ μλλ€. μ΄λ λ§€μ° λμ¨νκ² κ²°ν©λ μμ€ν μ λ§λ€μ΄, `NewsAgency` ν΄λμ€λ₯Ό μ ν λ³κ²½νμ§ μκ³ λ μλ‘μ΄ μλ¦Ό μ ν(μ: `PushNotifier`, `SlackNotifier`)μ μΆκ°ν μ μκ² ν©λλ€.
κ²°λ‘ : λμμΈ ν¨ν΄μΌλ‘ λ λμ μννΈμ¨μ΄ λ§λ€κΈ°
μ°λ¦¬λ μΈ κ°μ§ κΈ°λ³Έ λμμΈ ν¨ν΄βμ±κΈν€, ν©ν 리, μ΅μ λ²βμ μ΄ν΄λ³΄κ³ , νμ΄μ¬μμ μΌλ°μ μΈ μν€ν μ² λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄ μ΄λ€μ μ΄λ»κ² ꡬνν μ μλμ§ λ³΄μμ΅λλ€.
- μ±κΈν€ ν¨ν΄μ 곡μ 리μμ€λ₯Ό κ΄λ¦¬νλ λ° μλ²½ν λ¨μΌνκ³ μ μμ μΌλ‘ μ κ·Ό κ°λ₯ν μΈμ€ν΄μ€λ₯Ό μ 곡νμ§λ§, μ μ μνμ ν¨μ μ νΌνκΈ° μν΄ μ μ€νκ² μ¬μ©ν΄μΌ ν©λλ€.
- ν©ν 리 ν¨ν΄(ν©ν 리 λ©μλμ μΆμ ν©ν 리)μ κ°μ²΄ μμ±μ ν΄λΌμ΄μΈνΈ μ½λλ‘λΆν° λΆλ¦¬νλ κ°λ ₯ν λ°©λ²μ μ 곡νμ¬, μ°λ¦¬ μμ€ν μ λ λͺ¨λνλκ³ νμ₯ κ°λ₯νκ² λ§λλλ€.
- μ΅μ λ² ν¨ν΄μ κ°μ²΄κ° λ€λ₯Έ κ°μ²΄μ μν λ³νλ₯Ό ꡬλ νκ³ λ°μν μ μκ² ν¨μΌλ‘μ¨ κΉλν μ΄λ²€νΈ κΈ°λ° μν€ν μ²λ₯Ό κ°λ₯νκ² νκ³ , λμ¨ν κ²°ν©μ μ΄μ§ν©λλ€.
λμμΈ ν¨ν΄μ λ§μ€ν°νλ ν΅μ¬μ ꡬνμ μκΈ°νλ κ²μ΄ μλλΌ, κ·Έλ€μ΄ ν΄κ²°νλ λ¬Έμ λ₯Ό μ΄ν΄νλ κ²μ λλ€. μ€κ³ λ¬Έμ μ μ§λ©΄νμ λ, μλ €μ§ ν¨ν΄μ΄ κ²¬κ³ νκ³ , μ°μνλ©°, μ μ§λ³΄μ κ°λ₯ν ν΄κ²°μ± μ μ 곡ν μ μλμ§ μκ°ν΄λ³΄μΈμ. μ΄λ¬ν ν¨ν΄λ€μ κ°λ°μ ν΄ν·μ ν΅ν©ν¨μΌλ‘μ¨, κΈ°λ₯μ μΌ λΏλ§ μλλΌ κΉλνκ³ , 볡μλ ₯ μμΌλ©°, λ―Έλ μ±μ₯μ λλΉν μ μλ μ½λλ₯Ό μμ±ν μ μμ΅λλ€.