소프트웨어에 대한 모든 것

[디자인패턴][SOLID] 리스코프 치환 원칙 본문

시스템 설계 및 디자인/객체지향 SOLID

[디자인패턴][SOLID] 리스코프 치환 원칙

앤테바 2022. 3. 23. 19:09
반응형

리스코프 치환 원칙 (Liskov substitution principle)

리스코프 치환 원칙은 자식 클래스는 그의 부모 클래스를 대체할 수 있어야 한다고 합니다. 자식 클래스가 오류를 일으키지 않고 부모 클래스를 대신할 수 있도록 하는 것을 목표로 합니다. 자식 클래스는 부모 클래스의 행동 규약을 위반하면 안되는 것입니다.

 

어떤 경우에 리스코프 치환 원칙이 위반 될까요?

  • 자식 클래스가 부모 클래스의 변수 타입을 변경
  • 자식 클래스가 부모 클래스의 함수의 리턴 타입이나 파라미터를 변경
  • 자식 클래스가 부모 클래스의 함수를 원래 의도와 다르게 오버라이딩

 

글 보다는 코드로 이해하는 것이 더 빠릅니다.

from abc import ABC, abstractmethod


class Notificatioin(ABC):
    @abstractmethod
    def notify(self, message, email):
        pass

class Email(Notificatioin):
    def notify(self, message, email):
        print(f'send {message} to {email}')

class SMS(Notificatioin):
    def notify(self, message, phone):
        print(f'send {message} to {phone}')


notification = SMS()
notification.notify('hello world', 'james@abc.com')

위 예제에는 세 가지 클래스가 있습니다. Notification, EMail, SMS. Email과 SMS 클래스는 Notification 클래스를 상속 받았습니다. Email과 SMS는 message를 Notification의 notify() 함수를 통해서 전달하려는 것입니다.

 

EMail 클래스에서는 notify() 함수 사용에 문제가 없습니다. SMS 클래스에서는  notify() 함수의  두 번째 파라미터가 부모에서 정의한 email이 아니라 phone number 입니다. 그렇기 때문에 Notification의 notify() 함수를 올바르게 변경해야 합니다.

 

리스코프 치환 원칙을 준수해서 notify()함수를 수정합니다.

from abc import ABC, abstractmethod


class Notification(ABC):
    @abstractmethod
    def notify(self, message):
        pass


class Email(Notification):
    def __init__(self, email):
        self.email = email

    def notify(self, message):
        print(f'send {message} to {self.email}')


class SMS(Notification):
    def __init__(self, phone):
        self.phone = phone

    def notify(self, message):
        print(f'send {message} to {self.phone}')


class Contact:
    def __init__(self, name, email, phone):
        self.name = name
        self.email = email
        self.phone = phone


class NotificationManager:
    def __init__(self, notification):
        self.notification = notification

    def send(self, message):
        self.notification.notify(message)


contact = Contact('James', 'jamese@abc.com', '010-1111-2222')
sms_notification = Email(contact.phone)
email_notification = Email(contact.email)

notification_manager = NotificationManager(sms_notification)
notification_manager.send('hello james')

notification_manager.notification = email_notification
notification_manager.send('hi james')

요약

  • 리스코프 치환 원칙은, 자식 클래스는 반드시 그 부모 클래스를 대체할 수 있어야 한다.

 

참고한 자료:

Python Liskov Substitution Principle

https://velog.io/@tataki26/%EB%A6%AC%EC%8A%A4%EC%BD%94%ED%94%84-%EC%B9%98%ED%99%98-%EC%9B%90%EC%B9%99

 

반응형
Comments