{"id":13800039,"url":"https://github.com/ochococo/OOD-Principles-In-Swift","last_synced_at":"2025-05-13T08:32:37.226Z","repository":{"id":27818593,"uuid":"31308204","full_name":"ochococo/OOD-Principles-In-Swift","owner":"ochococo","description":"💎 The Principles of OOD (SOLID) based on Uncle Bob articles.","archived":false,"fork":false,"pushed_at":"2023-11-06T13:51:50.000Z","size":212,"stargazers_count":1898,"open_issues_count":1,"forks_count":158,"subscribers_count":75,"default_branch":"master","last_synced_at":"2025-04-05T14:08:32.855Z","etag":null,"topics":["computer-science","dependency-inversion-principle","interface-segregation-principle","liskov-substitution-principle","object-oriented","ood","ood-principles","open-closed-principle","playground","single-responsibility-principle","solid","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ochococo.png","metadata":{"files":{"readme":"README-ko-KR.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"github":"ochococo"}},"created_at":"2015-02-25T10:21:33.000Z","updated_at":"2025-04-04T16:53:39.000Z","dependencies_parsed_at":"2024-01-29T18:06:55.604Z","dependency_job_id":null,"html_url":"https://github.com/ochococo/OOD-Principles-In-Swift","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ochococo%2FOOD-Principles-In-Swift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ochococo%2FOOD-Principles-In-Swift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ochococo%2FOOD-Principles-In-Swift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ochococo%2FOOD-Principles-In-Swift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ochococo","download_url":"https://codeload.github.com/ochococo/OOD-Principles-In-Swift/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253903940,"owners_count":21981774,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["computer-science","dependency-inversion-principle","interface-segregation-principle","liskov-substitution-principle","object-oriented","ood","ood-principles","open-closed-principle","playground","single-responsibility-principle","solid","swift"],"created_at":"2024-08-04T00:01:08.598Z","updated_at":"2025-05-13T08:32:36.905Z","avatar_url":"https://github.com/ochococo.png","language":"Swift","readme":"\n객체지향 설계 원칙 in Swift 5\n=========================\n\nA short cheat-sheet with Playground ([OOD-Principles-In-Swift-ko-KR.playground.zip](https://raw.githubusercontent.com/ochococo/OOD-Principles-In-Swift/master/OOD-Principles-In-Swift-ko-KR.playground.zip)).\n\n👷 Project maintained by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki)\n\n🇰🇷 Translated by: [jwonyLee](https://github.com/jwonyLee) (JiWon Lee)\n\nS.O.L.I.D.\n==========\n\n* [The Single Responsibility Principle (단일 책임 원칙)](#-the-single-responsibility-principle-단일-책임-원칙)\n* [The Open Closed Principle (개방 폐쇄 원칙)](#-the-open-closed-principle-개방-폐쇄-원칙)\n* [The Liskov Substitution Principle (리스코프 치환 원칙)](#-the-liskov-substitution-principle-리스코프-치환-원칙)\n* [The Interface Segregation Principle (인터페이스 분리 원칙)](#-the-interface-segregation-principle-인터페이스-분리-원칙)\n* [The Dependency Inversion Principle (의존관계 역전 원칙)](#-the-dependency-inversion-principle-의존관계-역전-원칙)\n\n\n\n\n# 🔐 클래스에는 단 한 가지 변경 이유만 존재해야 한다. ([자세히](https://docs.google.com/open?id=0ByOwmqah_nuGNHEtcU5OekdDMkk))\n\n예시:\n\n```swift\n\nprotocol Openable {\n    mutating func open()\n}\n\nprotocol Closeable {\n    mutating func close()\n}\n\n// 문. 캡슐화된 상태를 갖고 있으며 메서드를 사용해 변경할 수 있다.\nstruct PodBayDoor: Openable, Closeable {\n\n    private enum State {\n        case open\n        case closed\n    }\n\n    private var state: State = .closed\n\n    mutating func open() {\n        state = .open\n    }\n\n    mutating func close() {\n        state = .closed\n    }\n}\n\n// 여는 일만 담당하며 안에 무엇이 들어있는 지, 어떻게 닫는 지 모른다.\nfinal class DoorOpener {\n    private var door: Openable\n\n    init(door: Openable) {\n        self.door = door\n    }\n\n    func execute() {\n        door.open()\n    }\n}\n\n// 닫는 일만 담당하며 안에 무엇이 들어있는 지, 어떻게 여는 지 모른다.\nfinal class DoorCloser {\n    private var door: Closeable\n\n    init(door: Closeable) {\n        self.door = door\n    }\n\n    func execute() {\n        door.close()\n    }\n}\n\nlet door = PodBayDoor()\n\n// ⚠️ `DoorOpeneer`만이 문을 여는 책임이 있다.\nlet doorOpener = DoorOpener(door: door)\ndoorOpener.execute()\n\n// ⚠️ 문을 닫은 후 다른 작업을 해야 하는 경우,\n// 알람을 켜는 것처럼 `DoorOpener` 클래스를 변경할 필요가 없다.\nlet doorCloser = DoorCloser(door: door)\ndoorCloser.execute()\n\n```\n\n# ✋ The Open Closed Principle (개방 폐쇄 원칙)\n\n클래스의 동작을 수정하지 않고, 확장할 수 있어야 한다. ([자세히](http://docs.google.com/a/cleancoder.com/viewer?a=v\u0026pid=explorer\u0026chrome=true\u0026srcid=0BwhCYaYDn8EgN2M5MTkwM2EtNWFkZC00ZTI3LWFjZTUtNTFhZGZiYmUzODc1\u0026hl=en))\n\n예시:\n \n```swift\n\nprotocol Shooting {\n    func shoot() -\u003e String\n}\n\n// 레이저 빔. 쏠 수 있다.\nfinal class LaserBeam: Shooting {\n    func shoot() -\u003e String {\n        return \"Ziiiiiip!\"\n    }\n}\n\n// 무기가 있고 모든 걸 한 번에 발사할 수 있다고 믿는다. 빵야! 빵야! 빵야!\nfinal class WeaponsComposite {\n\n    let weapons: [Shooting]\n\n    init(weapons: [Shooting]) {\n        self.weapons = weapons\n    }\n\n    func shoot() -\u003e [String] {\n        return weapons.map { $0.shoot() }\n    }\n}\n\nlet laser = LaserBeam()\nvar weapons = WeaponsComposite(weapons: [laser])\n\nweapons.shoot()\n\n// 로켓 런처. 로켓을 쏠 수 있다.\n// ⚠️ 로켓 런처를 추가하기 위해 기존 클래스에서 아무것도 변경할 필요가 없다.\nfinal class RocketLauncher: Shooting {\n    func shoot() -\u003e String {\n        return \"Whoosh!\"\n    }\n}\n\nlet rocket = RocketLauncher()\n\nweapons = WeaponsComposite(weapons: [laser, rocket])\nweapons.shoot()\n\n```\n\n# 👥 The Liskov Substitution Principle (리스코프 치환 원칙)\n\n파생된 클래스는 기본 클래스를 대체할 수 있어야 한다. ([자세히](http://docs.google.com/a/cleancoder.com/viewer?a=v\u0026pid=explorer\u0026chrome=true\u0026srcid=0BwhCYaYDn8EgNzAzZjA5ZmItNjU3NS00MzQ5LTkwYjMtMDJhNDU5ZTM0MTlh\u0026hl=en))\n\n예시:\n\n```swift\n\nlet requestKey: String = \"NSURLRequestKey\"\n\n// NSError 서브클래스. 추가적인 기능을 제공하지만 원래 기능을 엉망으로 만들진 않는다.\nclass RequestError: NSError {\n\n    var request: NSURLRequest? {\n        return self.userInfo[requestKey] as? NSURLRequest\n    }\n}\n\n// 데이터를 가져오지 못하면 RequestError를 반환한다.\nfunc fetchData(request: NSURLRequest) -\u003e (data: NSData?, error: RequestError?) {\n\n    let userInfo: [String:Any] = [requestKey : request]\n\n    return (nil, RequestError(domain:\"DOMAIN\", code:0, userInfo: userInfo))\n}\n\n// RequestError가 무엇인지 모르고 실패할 것이며, NSError를 반환한다.\nfunc willReturnObjectOrError() -\u003e (object: AnyObject?, error: NSError?) {\n\n    let request = NSURLRequest()\n    let result = fetchData(request: request)\n\n    return (result.data, result.error)\n}\n\nlet result = willReturnObjectOrError()\n\n// ⚠️ 확인. 이것은 내 관점에서 완벽한 NSError 인스턴스이다.\nlet error: Int? = result.error?.code\n\n// ⚠️ 하지만 이봐! 이게 무슨 일이죠? RequestError이기도 하다! 대단해!\nif let requestError = result.error as? RequestError {\n    requestError.request\n}\n\n```\n\n# 🍴 The Interface Segregation Principle (인터페이스 분리 원칙)\n\n클라이언트별로 세분화된 인터페이스를 만들어야 한다. ([자세히](http://docs.google.com/a/cleancoder.com/viewer?a=v\u0026pid=explorer\u0026chrome=true\u0026srcid=0BwhCYaYDn8EgOTViYjJhYzMtMzYxMC00MzFjLWJjMzYtOGJiMDc5N2JkYmJi\u0026hl=en))\n\n예시:\n \n```swift\n\n// 방문 사이트가 있다.\nprotocol LandingSiteHaving {\n    var landingSite: String { get }\n}\n\n// LandingSiteHaving 객체에 착륙할 수 있다.\nprotocol Landing {\n    func land(on: LandingSiteHaving) -\u003e String\n}\n\n// 페이로드가 있다.\nprotocol PayloadHaving {\n    var payload: String { get }\n}\n\n// 차량에서 페이로드를 가져올 수 있다 (예. Canadaarm을 통해).\nprotocol PayloadFetching {\n    func fetchPayload(vehicle: PayloadHaving) -\u003e String\n}\n\nfinal class InternationalSpaceStation: PayloadFetching {\n\n    // ⚠️ 우주 정거장은 SpaceXCRS8의 착륙 능력에 대해 전혀 모른다.\n    func fetchPayload(vehicle: PayloadHaving) -\u003e String {\n        return \"Deployed \\(vehicle.payload) at April 10, 2016, 11:23 UTC\"\n    }\n}\n\n// 바지선 - 착륙 지점이 있다 (well, you get the idea).\nfinal class OfCourseIStillLoveYouBarge: LandingSiteHaving {\n    let landingSite = \"a barge on the Atlantic Ocean\"\n}\n\n// 페이로드가 있고 착륙 지점이 있는 곳에 착륙할 수 있다.\n// 매우 제한된 우주 비행체라는 것을 안다.\nfinal class SpaceXCRS8: Landing, PayloadHaving {\n\n    let payload = \"BEAM and some Cube Sats\"\n\n    // ⚠️ CRS8 은 착륙지 정보만 알고 있다.\n    func land(on: LandingSiteHaving) -\u003e String {\n        return \"Landed on \\(on.landingSite) at April 8, 2016 20:52 UTC\"\n    }\n}\n\nlet crs8 = SpaceXCRS8()\nlet barge = OfCourseIStillLoveYouBarge()\nlet spaceStation = InternationalSpaceStation()\n\nspaceStation.fetchPayload(vehicle: crs8)\ncrs8.land(on: barge)\n```\n\n# 🔝 The Dependency Inversion Principle (의존관계 역전 원칙)\n\n구체화에 의존하지 말고 추상화에 의존하라. ([자세히](http://docs.google.com/a/cleancoder.com/viewer?a=v\u0026pid=explorer\u0026chrome=true\u0026srcid=0BwhCYaYDn8EgMjdlMWIzNGUtZTQ0NC00ZjQ5LTkwYzQtZjRhMDRlNTQ3ZGMz\u0026hl=en))\n\n예시:\n\n```swift\n\nprotocol TimeTraveling {\n    func travelInTime(time: TimeInterval) -\u003e String\n}\n\nfinal class DeLorean: TimeTraveling {\n\tfunc travelInTime(time: TimeInterval) -\u003e String {\n\t\treturn \"Used Flux Capacitor and travelled in time by: \\(time)s\"\n\t}\n}\n\nfinal class EmmettBrown {\n\tprivate let timeMachine: TimeTraveling\n\n\n    // ⚠️ Emmet Brown은 `DeLorean`을 구체적인 클래스인 `DeLorean`이 아닌, `TimeTraveling` 장치로 받는다.\n\tinit(timeMachine: TimeTraveling) {\n\t\tself.timeMachine = timeMachine\n\t}\n\n\tfunc travelInTime(time: TimeInterval) -\u003e String {\n\t\treturn timeMachine.travelInTime(time: time)\n\t}\n}\n\nlet timeMachine = DeLorean()\n\nlet mastermind = EmmettBrown(timeMachine: timeMachine)\nmastermind.travelInTime(time: -3600 * 8760)\n```\n\n\nInfo\n====\n\n📖 Descriptions from: [The Principles of OOD by Uncle Bob](http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod)\n","funding_links":["https://github.com/sponsors/ochococo"],"categories":["Swift","객체지향","Learning Swift: Advanced Topics"],"sub_categories":["웹","Design Patterns"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fochococo%2FOOD-Principles-In-Swift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fochococo%2FOOD-Principles-In-Swift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fochococo%2FOOD-Principles-In-Swift/lists"}