티스토리 뷰

SOLID? 객체 지향 프로그래밍 및 설계의 다섯가지 기본 원칙

왜? 유지 보수와 확장이 쉬운 시스템을 만들고자

 

SRP, Single Responsibility Principle 단일 책임 원칙

객체는 단 하나의 책임만 가져야 한다.

클래스는 그 책임을 완전히 캡슐화해야 한다.

책임 - 변경하려는 이유

 

예)

 

보고서를 편집하고 출력하는 모듈

이 모듈은 두 가지 이유로 변경될 수 있다.

1. 보고서의 내용 (실질적)

2. 보고서의 형식 (꾸미기)

따라서 분리된 클래스나 모듈로 나누어야 한다.

다른 시기에 다른 이유로 변경되어야 하는 두 가지를 묶는 것은 나쁜 설계일 수 있다.

 

OCP, Open-Closed Principle 개방-폐쇄 원칙

확장에 대해 열려 있어야 하고, 수정에 대해서 닫혀 있어야 한다.

개방-폐쇄 원칙이 잘 적용되면, 기능을 추가하거나 변경해야 할 때 이미 제대로 동작하고 있던 원래 코드를 변경하지 않아도, 기존의 코드에 새로운 코드를 추가함으로써 기능의 추가나 변경이 가능하다.

추상화는 개방-폐쇄 원칙의 핵심요소

 

예) 동일한 기능 프로토콜로 정의하기

카드 추가하는 기능이 있는데, 롯데카드가 추가됐다고 모든 부분을 수정할 필요없이, 카드라는 프로토콜에 카드가 가질 성질들을 적어놓고, 새로운 카드가 추가되어도 다른 부분은 수정안해도 되도록하는 것

LSP, Liskov Substitution Principle 리스코프 치환 원칙

자료형 S가 자료형 T의 하위형이라면, 프로그램에서 자료형 T의 객체는 프로그램의 속성을 변경하지 않고 자료형 S의 객체로 교체할 수 있다.

자식 클래스는 부모 클래스 동작을 바꾸지 않는다.

 

예)

 

유저 서비스는 contact라는 역할을 한다.

그런데 밸리드유저서비스는 유저의 나이가 17세 이상에게만 contact를 한다.

이렇게되면 리스코프 치환원칙 위배된다.

class UserService {
    func contact(user: User) {
        // Retrieve user from database
    }
}

class ValidUserService: UserService {
    override func contact(user: User) {
        guard user.age > 17 else { return }

        super.contact(user: User)
    }
}

 

아래와 같이 조건을 추가하여 문제를 해결할 수 있다.

class UserService {
    func contact(user: User, minAge: Int = 0) {
        guard user.age > minAge else { return }
        // Retrieve user from database
    }
}

 

 

 

 

참고: https://www.raulferrergarcia.com/en/solid-principles-application-to-swift-development/

 ISP, Interface Segregation Principle 인터페이스 분리 원칙

자신이 이용하지 않는 메서드에 의존하지 않아야 한다.

프로토콜 동물움직임

  func 달리기

  func 날기

  func 수영하기

라고 정의하면

 

고래는 동물인데 달리기와 날기  func는 사용하지 않게된다.

그래서

  protocol 달리기

  func 달리기

  protocol 수영하기

  func 수영

이런식으로 분리해서

  악어: 달리기, 수영하기

  고래: 수영하기

이렇게 사용하는게 좋다.

 

 

DIP, Dependency Inversion Priciple 의존성 역전 원칙

상위 계층이 하위 계층에 의존하는 관계를 역전시킴으로써 상위 계층이 하위 계층의 구현으로부터 독립되게 한다.

 

첫째, 상위 모듈은 하위 모듈에 의존해서는 안된다. 상위 모듈과 하위 모듈 모두 추상화에 의존해야 한다.

둘째, 추상화는 세부 사항에 의존해서는 안된다. 세부사항이 추상화에 의존해야 한다.

 

예)

핸들러는 파일시스템매니저에 의존하고있다.

class Handler {

    let fm = FilesystemManager()

    func handle(string: String) {
        fm.save(string: string)
    }
}

class FilesystemManager {

    func save(string: String) {
        // Open a file
        // Save the string in this file
        // Close the file
    }
}

 

 

스토리지라는 프로토콜을 만들어서 해결한다.

 

class Handler {

    let storage: Storage

    init(storage: Storage) {
        self.storage = storage
    }

    func handle(string: String) {
        storage.save(string: string)
    }
}

protocol Storage {

   func save(string: String)
}

class FilesystemManager: Storage {

    func save(string: String) {
        // Open a file in read-mode
        // Save the string in this file
        // Close the file
    }
}

class DatabaseManager: Storage {

    func save(string: String) {
        // Connect to the database
        // Execute the query to save the string in a table
        // Close the connection
    }
}

참고 https://marcosantadev.com/solid-principles-applied-swift/

 

 

 

 

 

댓글
공지사항