Created at : 2024-04-11 03:35
Auther: Soo.Y

SOLID μ›μΉ™μ΄λž€

SOLID 원칙은 객체 μ§€ν–₯ ν”„λ‘œκ·Έλž˜λ°κ³Ό λ””μžμΈμ—μ„œ μ€‘μš”ν•œ 5κ°€μ§€ 원칙을 λ‚˜νƒ€λ‚Έ μ›μΉ™μž…λ‹ˆλ‹€. 이 원칙듀은 μ†Œν”„νŠΈμ›¨μ–΄λ₯Ό 더 μ΄ν•΄ν•˜κΈ° 쉽고, μœ μ§€λ³΄μˆ˜ν•˜κΈ° 쉽고 ν™•μž₯ κ°€λŠ₯ν•˜κ²Œ λ§Œλ“œλŠ”λ° 도움이 λ©λ‹ˆλ‹€. SOILDλŠ” λ‹€μŒκ³Ό 같은 μ›μΉ™λ“€μ˜ μ•½μžμž…λ‹ˆλ‹€.

  1. Single Responsibility Principle (단일 μ±…μž„ 원칙)
  2. Open/Closed Principle (개방/폐쇄 원칙)
  3. Liskov Substitution Principle (λ¦¬μŠ€μ½”ν”„ μΉ˜ν™˜ 원칙)
  4. Interface Segregation Principle (μΈν„°νŽ˜μ΄μŠ€ 뢄리 원칙)
  5. Dependency Inversion Principle (μ˜μ‘΄μ„± μ—­μ „ 원칙)

S (Single Responsibility Principle)

단일 μ±…μž„ 원칙은 ν΄λž˜μŠ€κ°€ ν•˜λ‚˜μ˜ μ±…μž„λ§Œμ„ κ°€μ Έμ•Ό ν•œλ‹€λŠ” μ›μΉ™μž…λ‹ˆλ‹€. μ—¬κΈ°μ„œ λ§ν•˜λŠ” μ±…μž„μ€ β€˜λ³€κ²½λ˜μ–΄μ•Ό ν•˜λŠ” μ΄μœ β€™ 라고 ν•˜λŠ”λ° μ–΄λ–»κ²Œ 보면 κΈ°λŠ₯이라고 μ΄ν•΄ν•˜λ©΄ 쉽닀고 μƒκ°ν–ˆλ‹€.

LoggerλŠ” 둜그λ₯Ό 좜λ ₯ν•˜λŠ” κΈ°λŠ₯만 κ°€μ§€κ³  있고 EmailSenderλŠ” 이메일을 μ „μ†‘ν•˜λŠ” κΈ°λŠ₯만 λ³΄μœ ν•˜κ³  μžˆλ‹€. OrderλŠ” 주문을 μ²˜λ¦¬ν•˜λŠ” κΈ°λŠ₯만 λ³΄μœ ν•˜κ³  μžˆλ‹€. μ—¬κΈ°μ„œ __init__μ—μ„œ Logger와 EmailSender 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•΄μ„œ κΈ°λŠ₯을 μ‚¬μš©ν•  뿐 Logger 및 EmailSender의 κΈ°λŠ₯을 문제λ₯Ό λ‹΄λ‹Ήν•˜μ§€ μ•ŠλŠ”λ‹€. κ·Έλž˜μ„œ Logger에 κΈ°λŠ₯이 λ¬Έμ œκ°€ λ°œμƒν•˜λ©΄ Logger ν΄λž˜μŠ€μ—μ„œλ§Œ 였λ₯˜λ₯Ό μˆ˜μ •ν•˜λ©΄ λœλ‹€.

class Logger:
    """둜그 기둝 μ±…μž„λ§Œμ„ 가짐"""
    def log(self, message: str):
        print(f"Log: {message}")
 
class EmailSender:
    """이메일 전솑 μ±…μž„λ§Œμ„ 가짐"""
    def send_email(self, to: str, content: str):
        print(f"Sending email to {to}: {content}")
 
class Order:
    """μ£Όλ¬Έ κ΄€λ ¨ μ±…μž„μ„ 가짐. λ‘œκΉ…κ³Ό 이메일 전솑은 μ™ΈλΆ€ μ„œλΉ„μŠ€λ₯Ό 이용"""
    def __init__(self):
        self.logger = Logger()
        self.email_sender = EmailSender()
 
    def process_order(self, user_email: str):
        # 주문 처리 둜직
        self.logger.log("Order processed.")
        self.email_sender.send_email(user_email, "Your order has been processed.")
 
# μ‚¬μš© μ˜ˆμ‹œ
order = Order()
order.process_order("user@example.com")

O (Open-Closed Principle)

개방-폐쇄 원칙은 μ†Œν”„νŠΈμ›¨μ–΄ 개체(클래슀, λͺ¨λ“ˆ, ν•¨μˆ˜ λ“±)λŠ” ν™•μž₯에 λŒ€ν•΄μ„œλŠ” μ—΄λ € μžˆμ–΄μ•Ό ν•˜κ³  μˆ˜μ •μ— λŒ€ν•΄μ„œλŠ” λ‹«ν˜€ μžˆμ–΄μ•Ό ν•œλ‹€λŠ” μ›μΉ™μž…λ‹ˆλ‹€.

λΆ€λͺ¨ 클래슀인 Reportκ°€ CSVλ₯Ό μ²˜λ¦¬ν•˜λŠ” report 클래슀, JSON을 μ²˜λ¦¬ν•˜λŠ” report 클래슀둜 λ‹€μ–‘ν•˜κ²Œ λ§Œλ“€ 수 μžˆλ‹€.

from abc import ABC, abstractmethod
 
class Report(ABC):
    @abstracmethod
    def generate(self):
        pass
 
class CSVReport(Report):
    def generate(self):
	    """csv reportλ₯Ό μ²˜λ¦¬ν•˜λŠ” 둜직"""
        return "CSV report data"
 
class JSONReport(Report):
    def generate(self):
	    """JSON reportλ₯Ό μ²˜λ¦¬ν•˜λŠ” 둜직"""
        return "JSON report data"

μ’€ 더 λ³΅μž‘ν•œ μ˜ˆμ‹œλ₯Ό μ‚΄νŽ΄λ³΄μž. πŸ€” Discount 좔상 클래슀λ₯Ό μ„ μ–Έν•˜κ³  λͺ¨λ“  ν• μΈμ˜ 기본을 μ •μ˜ν•˜λ©° μ‹€μ œ 할인 λ‘œμ§μ€ 이λ₯Ό μƒμ†λ°›λŠ” ꡬ체적인 클래슀(NoDiscount, PercentageDiscount, FixedDiscount)μ—μ„œ κ΅¬ν˜„λœ μ˜ˆμ‹œμž…λ‹ˆλ‹€. Product ν΄λž˜μŠ€λŠ” 할인 객체λ₯Ό λ°›μ•„μ„œ ν• μΈλœ 가격을 κ³„μ‚°ν•©λ‹ˆλ‹€. 이 λ°©μ‹μœΌλ‘œ μƒˆλ‘œμš΄ 할인 μœ ν˜•μ„ μΆ”κ°€ν•˜κ³  싢을 λ•Œ Discountλ₯Ό 상속 λ°›λŠ” μƒˆλ‘œμš΄ 클래슀λ₯Ό λ§Œλ“€κΈ°λ§Œ ν•˜λ©΄ λ˜λ―€λ‘œ, κΈ°μ‘΄ μ½”λ“œλ₯Ό λ³€κ²½ν•  ν•„μš” 없이 ν™•μž₯ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

from abc import ABC, abstractmethod
 
class Discount(ABC):
    @abstractmethod
    def apply(self, price: float) -> float:
        pass
 
class NoDiscount(Discount):
    def apply(self, price: float) -> float:
        return price
 
class PercentageDiscount(Discount):
    def __init__(self, percentage: float):
        self.percentage = percentage
 
    def apply(self, price: float) -> float:
        return price - (price * self.percentage / 100)
 
class FixedDiscount(Discount):
    def __init__(self, discount: float):
        self.discount = discount
 
    def apply(self, price: float) -> float:
        return max(0, price - self.discount)
 
class Product:
    def __init__(self, name: str, price: float, discount: Discount):
        self.name = name
        self.price = price
        self.discount = discount
 
    def price_after_discount(self):
        return self.discount.apply(self.price)
 
# μ‚¬μš© μ˜ˆμ‹œ
no_discount_product = Product("Product with no discount", 100.0, NoDiscount())
percentage_discount_product = Product("Product with 10% discount", 100.0, PercentageDiscount(10))
fixed_discount_product = Product("Product with $20 discount", 100.0, FixedDiscount(20))
 
print(no_discount_product.price_after_discount())
print(percentage_discount_product.price_after_discount())
print(fixed_discount_product.price_after_discount())

L (Liskov Substitution Principle)

λ¦¬μŠ€μ½”ν”„ μΉ˜ν™˜ 원칙은 ν”„λ‘œκ·Έλž¨μ΄ 정확성을 μžƒμ§€ μ•ŠμœΌλ©΄μ„œ ν•˜μœ„ νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμœ„ νƒ€μž… 객체둜 μΉ˜ν™˜ν•  수 μžˆμ–΄μ•Ό ν•œλ‹€λŠ” μ›μΉ™μž…λ‹ˆλ‹€.

I (Interface Segregation Principle)

μΈν„°νŽ˜μ΄μŠ€ 뢄리 원칙은 ν΄λΌμ΄μ–ΈνŠΈκ°€ μžμ‹ μ΄ μ΄μš©ν•˜μ§€ μ•ŠλŠ” λ©”μ„œλ“œμ— μ˜μ‘΄ν•˜μ§€ μ•Šμ•„μ•Ό ν•œλ‹€λŠ” μ›μΉ™μž…λ‹ˆλ‹€.

D (Dependency Inversion Principle)

의쑴 μ—­μ „ 원칙은 μƒμœ„ λͺ¨λ“ˆμ΄ ν•˜μœ„ λͺ¨λ“ˆμ— μ˜μ‘΄ν•˜λ©΄ μ•ˆ 되며, λ‘˜ λ‹€ 좔상화에 μ˜μ‘΄ν•΄μ•Ό ν•œλ‹€λŠ” μ›μΉ™μž…λ‹ˆλ‹€.

κ΄€λ ¨ λ¬Έμ„œ

https://wikidocs.net/168361