The Open Closed Principle says that “Software Entities (classes, modules, functions, etc) should be open for extension, but closed for modification”.
OCP에 따르면,
Software Entities는 확장할 수 있어야 하지만, 변경할 수는 없어야 한다.
class Person {
private let name: String
private let age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
class House {
private var residents: [Person]
init(residents: [Person]) {
self.residents = residents
}
func add(_ resident: Person) {
residents.append(resident)
}
}
protocol Resident {}
class Person: Resident {
// ...
}
class House {
private var residents: [Resident]
init(residents: [Resident]) {
self.residents = residents
}
func add(_ resident: Resident) {
residents.append(resident)
}
}
왼쪽 예시를 보면, Person이라는 타입과는 다른 타입이 필요해서 NewPerson 타입을 만든다면,
House에서는 내부에 있는 Person 타입들을 모두 NewPerson 타입으로 바꾸어야 함
즉, NewPerson으로 확장하려 하는데, House 에서는 변동이 생기기 때문에 OCP를 만족하지 못한다
만약, 그냥 Person 타입의 내부를 바꾼다면, 이 또한 Person 타입에 변동이 생기는 것이기 때문에 OCP를 만족하지 못한다
따라서, OCP를 따르지 않으면, 한 가지를 확장하려 할 때, 변동을 줘야 하는 요소가 생기게 된다
House 타입은 Resident라는 프로토콜을 의존하고 있고,
Person도 Resident라는 프로토콜을 받아와 사용하기 때문에,
NewPerson이라는 타입이 Resident를 따르도록 형성된다면, House에는 아무 변화를 주지 않아도 된다
enum DeeplinkType {
case home
case profile
}
protocol Deeplink {
var type: DeeplinkType { get }
}
class HomeDeeplink: Deeplink {
let type: DeeplinkType = .home
func executeHome() {
// Presents the main screen
}
}
class ProfileDeeplink: Deeplink {
let type: DeeplinkType = .profile
func executeProfile() {
// Presents the profile screen
}
}
class Router {
func execute(_ deeplink: Deeplink) {
switch deeplink.type {
case .home:
(deeplink as? HomeDeeplink)?.executeHome()
case .profile:
(deeplink as? ProfileDeeplink)?.executeProfile()
}
}
}
위 예시는 OCP를 따르지 않음
DeeplinkType에 새로운 case를 추가하게 되면
Router의 execute()에도 새로운 case를 넣어줘야 하기 때문 !
나는 그저 DeeplinkType를 확장했을 뿐인데, Router 클래스에도 변화를 줘야한다고 ..?!
많은 경우에 enum의 사용은 이렇게 다른 곳에서의 변동을 발생시킨다 ㅠㅠ
간단하게 case만 추가해주면 되는 때도 있겠지만, 완전 복잡한 로직이 들어가면 사고 …
protocol Deeplink {
func execute()
}
class HomeDeeplink: Deeplink {
func execute() {
// Presents the main screen
}
}
class ProfileDeeplink: Deeplink {
func execute() {
// Presents the Profile screen
}
}
class Router {
func execute(_ deeplink: Deeplink) {
deeplink.execute()
}
}
이런 모습으로 바뀌게 됨 !
class SettingsDeeplink: Deeplink {
func execute() {
// Present the Settings Screen
}
}
새로운 Deeplink 타입을 추가하게 되어도,
Router에는 아무 변동이 생기지 않음