Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/ochococo/ood-principles-in-swift

๐Ÿ’Ž The Principles of OOD (SOLID) based on Uncle Bob articles.
https://github.com/ochococo/ood-principles-in-swift

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

Last synced: 25 days ago
JSON representation

๐Ÿ’Ž The Principles of OOD (SOLID) based on Uncle Bob articles.

Awesome Lists containing this project

README

        

๊ฐ์ฒด์ง€ํ–ฅ ์„ค๊ณ„ ์›์น™ in Swift 5
=========================

A 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)).

๐Ÿ‘ท Project maintained by: [@nsmeme](http://twitter.com/nsmeme) (Oktawian Chojnacki)

๐Ÿ‡ฐ๐Ÿ‡ท Translated by: [jwonyLee](https://github.com/jwonyLee) (JiWon Lee)

S.O.L.I.D.
==========

* [The Single Responsibility Principle (๋‹จ์ผ ์ฑ…์ž„ ์›์น™)](#-the-single-responsibility-principle-๋‹จ์ผ-์ฑ…์ž„-์›์น™)
* [The Open Closed Principle (๊ฐœ๋ฐฉ ํ์‡„ ์›์น™)](#-the-open-closed-principle-๊ฐœ๋ฐฉ-ํ์‡„-์›์น™)
* [The Liskov Substitution Principle (๋ฆฌ์Šค์ฝ”ํ”„ ์น˜ํ™˜ ์›์น™)](#-the-liskov-substitution-principle-๋ฆฌ์Šค์ฝ”ํ”„-์น˜ํ™˜-์›์น™)
* [The Interface Segregation Principle (์ธํ„ฐํŽ˜์ด์Šค ๋ถ„๋ฆฌ ์›์น™)](#-the-interface-segregation-principle-์ธํ„ฐํŽ˜์ด์Šค-๋ถ„๋ฆฌ-์›์น™)
* [The Dependency Inversion Principle (์˜์กด๊ด€๊ณ„ ์—ญ์ „ ์›์น™)](#-the-dependency-inversion-principle-์˜์กด๊ด€๊ณ„-์—ญ์ „-์›์น™)

# ๐Ÿ” ํด๋ž˜์Šค์—๋Š” ๋‹จ ํ•œ ๊ฐ€์ง€ ๋ณ€๊ฒฝ ์ด์œ ๋งŒ ์กด์žฌํ•ด์•ผ ํ•œ๋‹ค. ([์ž์„ธํžˆ](https://docs.google.com/open?id=0ByOwmqah_nuGNHEtcU5OekdDMkk))

์˜ˆ์‹œ:

```swift

protocol Openable {
mutating func open()
}

protocol Closeable {
mutating func close()
}

// ๋ฌธ. ์บก์Šํ™”๋œ ์ƒํƒœ๋ฅผ ๊ฐ–๊ณ  ์žˆ์œผ๋ฉฐ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.
struct PodBayDoor: Openable, Closeable {

private enum State {
case open
case closed
}

private var state: State = .closed

mutating func open() {
state = .open
}

mutating func close() {
state = .closed
}
}

// ์—ฌ๋Š” ์ผ๋งŒ ๋‹ด๋‹นํ•˜๋ฉฐ ์•ˆ์— ๋ฌด์—‡์ด ๋“ค์–ด์žˆ๋Š” ์ง€, ์–ด๋–ป๊ฒŒ ๋‹ซ๋Š” ์ง€ ๋ชจ๋ฅธ๋‹ค.
final class DoorOpener {
private var door: Openable

init(door: Openable) {
self.door = door
}

func execute() {
door.open()
}
}

// ๋‹ซ๋Š” ์ผ๋งŒ ๋‹ด๋‹นํ•˜๋ฉฐ ์•ˆ์— ๋ฌด์—‡์ด ๋“ค์–ด์žˆ๋Š” ์ง€, ์–ด๋–ป๊ฒŒ ์—ฌ๋Š” ์ง€ ๋ชจ๋ฅธ๋‹ค.
final class DoorCloser {
private var door: Closeable

init(door: Closeable) {
self.door = door
}

func execute() {
door.close()
}
}

let door = PodBayDoor()

// โš ๏ธ `DoorOpeneer`๋งŒ์ด ๋ฌธ์„ ์—ฌ๋Š” ์ฑ…์ž„์ด ์žˆ๋‹ค.
let doorOpener = DoorOpener(door: door)
doorOpener.execute()

// โš ๏ธ ๋ฌธ์„ ๋‹ซ์€ ํ›„ ๋‹ค๋ฅธ ์ž‘์—…์„ ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ,
// ์•Œ๋žŒ์„ ์ผœ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ `DoorOpener` ํด๋ž˜์Šค๋ฅผ ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.
let doorCloser = DoorCloser(door: door)
doorCloser.execute()

```

# โœ‹ The Open Closed Principle (๊ฐœ๋ฐฉ ํ์‡„ ์›์น™)

ํด๋ž˜์Šค์˜ ๋™์ž‘์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ , ํ™•์žฅํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ([์ž์„ธํžˆ](http://docs.google.com/a/cleancoder.com/viewer?a=v&pid=explorer&chrome=true&srcid=0BwhCYaYDn8EgN2M5MTkwM2EtNWFkZC00ZTI3LWFjZTUtNTFhZGZiYmUzODc1&hl=en))

์˜ˆ์‹œ:

```swift

protocol Shooting {
func shoot() -> String
}

// ๋ ˆ์ด์ € ๋น”. ์  ์ˆ˜ ์žˆ๋‹ค.
final class LaserBeam: Shooting {
func shoot() -> String {
return "Ziiiiiip!"
}
}

// ๋ฌด๊ธฐ๊ฐ€ ์žˆ๊ณ  ๋ชจ๋“  ๊ฑธ ํ•œ ๋ฒˆ์— ๋ฐœ์‚ฌํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๋ฏฟ๋Š”๋‹ค. ๋นต์•ผ! ๋นต์•ผ! ๋นต์•ผ!
final class WeaponsComposite {

let weapons: [Shooting]

init(weapons: [Shooting]) {
self.weapons = weapons
}

func shoot() -> [String] {
return weapons.map { $0.shoot() }
}
}

let laser = LaserBeam()
var weapons = WeaponsComposite(weapons: [laser])

weapons.shoot()

// ๋กœ์ผ“ ๋Ÿฐ์ฒ˜. ๋กœ์ผ“์„ ์  ์ˆ˜ ์žˆ๋‹ค.
// โš ๏ธ ๋กœ์ผ“ ๋Ÿฐ์ฒ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด ๊ธฐ์กด ํด๋ž˜์Šค์—์„œ ์•„๋ฌด๊ฒƒ๋„ ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.
final class RocketLauncher: Shooting {
func shoot() -> String {
return "Whoosh!"
}
}

let rocket = RocketLauncher()

weapons = WeaponsComposite(weapons: [laser, rocket])
weapons.shoot()

```

# ๐Ÿ‘ฅ The Liskov Substitution Principle (๋ฆฌ์Šค์ฝ”ํ”„ ์น˜ํ™˜ ์›์น™)

ํŒŒ์ƒ๋œ ํด๋ž˜์Šค๋Š” ๊ธฐ๋ณธ ํด๋ž˜์Šค๋ฅผ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ([์ž์„ธํžˆ](http://docs.google.com/a/cleancoder.com/viewer?a=v&pid=explorer&chrome=true&srcid=0BwhCYaYDn8EgNzAzZjA5ZmItNjU3NS00MzQ5LTkwYjMtMDJhNDU5ZTM0MTlh&hl=en))

์˜ˆ์‹œ:

```swift

let requestKey: String = "NSURLRequestKey"

// NSError ์„œ๋ธŒํด๋ž˜์Šค. ์ถ”๊ฐ€์ ์ธ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์ง€๋งŒ ์›๋ž˜ ๊ธฐ๋Šฅ์„ ์—‰๋ง์œผ๋กœ ๋งŒ๋“ค์ง„ ์•Š๋Š”๋‹ค.
class RequestError: NSError {

var request: NSURLRequest? {
return self.userInfo[requestKey] as? NSURLRequest
}
}

// ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค์ง€ ๋ชปํ•˜๋ฉด RequestError๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
func fetchData(request: NSURLRequest) -> (data: NSData?, error: RequestError?) {

let userInfo: [String:Any] = [requestKey : request]

return (nil, RequestError(domain:"DOMAIN", code:0, userInfo: userInfo))
}

// RequestError๊ฐ€ ๋ฌด์—‡์ธ์ง€ ๋ชจ๋ฅด๊ณ  ์‹คํŒจํ•  ๊ฒƒ์ด๋ฉฐ, NSError๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
func willReturnObjectOrError() -> (object: AnyObject?, error: NSError?) {

let request = NSURLRequest()
let result = fetchData(request: request)

return (result.data, result.error)
}

let result = willReturnObjectOrError()

// โš ๏ธ ํ™•์ธ. ์ด๊ฒƒ์€ ๋‚ด ๊ด€์ ์—์„œ ์™„๋ฒฝํ•œ NSError ์ธ์Šคํ„ด์Šค์ด๋‹ค.
let error: Int? = result.error?.code

// โš ๏ธ ํ•˜์ง€๋งŒ ์ด๋ด! ์ด๊ฒŒ ๋ฌด์Šจ ์ผ์ด์ฃ ? RequestError์ด๊ธฐ๋„ ํ•˜๋‹ค! ๋Œ€๋‹จํ•ด!
if let requestError = result.error as? RequestError {
requestError.request
}

```

# ๐Ÿด The Interface Segregation Principle (์ธํ„ฐํŽ˜์ด์Šค ๋ถ„๋ฆฌ ์›์น™)

ํด๋ผ์ด์–ธํŠธ๋ณ„๋กœ ์„ธ๋ถ„ํ™”๋œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค. ([์ž์„ธํžˆ](http://docs.google.com/a/cleancoder.com/viewer?a=v&pid=explorer&chrome=true&srcid=0BwhCYaYDn8EgOTViYjJhYzMtMzYxMC00MzFjLWJjMzYtOGJiMDc5N2JkYmJi&hl=en))

์˜ˆ์‹œ:

```swift

// ๋ฐฉ๋ฌธ ์‚ฌ์ดํŠธ๊ฐ€ ์žˆ๋‹ค.
protocol LandingSiteHaving {
var landingSite: String { get }
}

// LandingSiteHaving ๊ฐ์ฒด์— ์ฐฉ๋ฅ™ํ•  ์ˆ˜ ์žˆ๋‹ค.
protocol Landing {
func land(on: LandingSiteHaving) -> String
}

// ํŽ˜์ด๋กœ๋“œ๊ฐ€ ์žˆ๋‹ค.
protocol PayloadHaving {
var payload: String { get }
}

// ์ฐจ๋Ÿ‰์—์„œ ํŽ˜์ด๋กœ๋“œ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค (์˜ˆ. Canadaarm์„ ํ†ตํ•ด).
protocol PayloadFetching {
func fetchPayload(vehicle: PayloadHaving) -> String
}

final class InternationalSpaceStation: PayloadFetching {

// โš ๏ธ ์šฐ์ฃผ ์ •๊ฑฐ์žฅ์€ SpaceXCRS8์˜ ์ฐฉ๋ฅ™ ๋Šฅ๋ ฅ์— ๋Œ€ํ•ด ์ „ํ˜€ ๋ชจ๋ฅธ๋‹ค.
func fetchPayload(vehicle: PayloadHaving) -> String {
return "Deployed \(vehicle.payload) at April 10, 2016, 11:23 UTC"
}
}

// ๋ฐ”์ง€์„  - ์ฐฉ๋ฅ™ ์ง€์ ์ด ์žˆ๋‹ค (well, you get the idea).
final class OfCourseIStillLoveYouBarge: LandingSiteHaving {
let landingSite = "a barge on the Atlantic Ocean"
}

// ํŽ˜์ด๋กœ๋“œ๊ฐ€ ์žˆ๊ณ  ์ฐฉ๋ฅ™ ์ง€์ ์ด ์žˆ๋Š” ๊ณณ์— ์ฐฉ๋ฅ™ํ•  ์ˆ˜ ์žˆ๋‹ค.
// ๋งค์šฐ ์ œํ•œ๋œ ์šฐ์ฃผ ๋น„ํ–‰์ฒด๋ผ๋Š” ๊ฒƒ์„ ์•ˆ๋‹ค.
final class SpaceXCRS8: Landing, PayloadHaving {

let payload = "BEAM and some Cube Sats"

// โš ๏ธ CRS8 ์€ ์ฐฉ๋ฅ™์ง€ ์ •๋ณด๋งŒ ์•Œ๊ณ  ์žˆ๋‹ค.
func land(on: LandingSiteHaving) -> String {
return "Landed on \(on.landingSite) at April 8, 2016 20:52 UTC"
}
}

let crs8 = SpaceXCRS8()
let barge = OfCourseIStillLoveYouBarge()
let spaceStation = InternationalSpaceStation()

spaceStation.fetchPayload(vehicle: crs8)
crs8.land(on: barge)
```

# ๐Ÿ” The Dependency Inversion Principle (์˜์กด๊ด€๊ณ„ ์—ญ์ „ ์›์น™)

๊ตฌ์ฒดํ™”์— ์˜์กดํ•˜์ง€ ๋ง๊ณ  ์ถ”์ƒํ™”์— ์˜์กดํ•˜๋ผ. ([์ž์„ธํžˆ](http://docs.google.com/a/cleancoder.com/viewer?a=v&pid=explorer&chrome=true&srcid=0BwhCYaYDn8EgMjdlMWIzNGUtZTQ0NC00ZjQ5LTkwYzQtZjRhMDRlNTQ3ZGMz&hl=en))

์˜ˆ์‹œ:

```swift

protocol TimeTraveling {
func travelInTime(time: TimeInterval) -> String
}

final class DeLorean: TimeTraveling {
func travelInTime(time: TimeInterval) -> String {
return "Used Flux Capacitor and travelled in time by: \(time)s"
}
}

final class EmmettBrown {
private let timeMachine: TimeTraveling

// โš ๏ธ Emmet Brown์€ `DeLorean`์„ ๊ตฌ์ฒด์ ์ธ ํด๋ž˜์Šค์ธ `DeLorean`์ด ์•„๋‹Œ, `TimeTraveling` ์žฅ์น˜๋กœ ๋ฐ›๋Š”๋‹ค.
init(timeMachine: TimeTraveling) {
self.timeMachine = timeMachine
}

func travelInTime(time: TimeInterval) -> String {
return timeMachine.travelInTime(time: time)
}
}

let timeMachine = DeLorean()

let mastermind = EmmettBrown(timeMachine: timeMachine)
mastermind.travelInTime(time: -3600 * 8760)
```

Info
====

๐Ÿ“– Descriptions from: [The Principles of OOD by Uncle Bob](http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod)