-
[Swift] Objected Oriented Programming in Swift (raywenderlich ๋ฒ์ญ)Swift 2022. 1. 13. 19:57
์ฌ๋ฌผ์ ๊ฐ์ฒด ์งํฅ์ ์ธ ๋ฐฉ์์ผ๋ก ์ค๊ณํ๋ ๊ฒ์ ์ผ๋ฐ์ ์ธ ๊ฐ๋ ์ ๋ณด๋ค ๊ตฌ์ฒด์ ์ธ ์ ํ์ผ๋ก ํ์ฅํ๋ ๊ฒ์์๋ถํฐ ์์๋๋ค. ์ฌ๊ธฐ์๋ ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ์ฌ์ฉํ์ฌ ๋ฎค์ง์ปฌ ๋ฐด๋๋ฅผ ๋ง๋ค์ด ๋ณผ ๊ฒ์ด๋ค. ์๋ ํ๋ฅผ ์ ๊ธฐ์ ๊ฐ๊ณ๋๋ผ๊ณ ์๊ฐํ๋ฉด, ์์๊ณผ ๋ถ๋ชจ ์ฌ์ด์ ๊ด๊ณ๋ is-a์ด๋ค. ์ฆ, Guitar is-a Instrument๋ผ๊ณ ๋งํ ์ ์๋ ๊ฒ์ด๋ค.
ใ
ค
ใ
ค
Properties
// 1 class Instrument { // 2 let brand: String // 3 init(brand: String) { //4 self.brand = brand } }classํค์๋๋ฅผ ์ด์ฉํด์ Instrument๋ผ๋base class๋ฅผ ๋ง๋ค์๋๋ฐ, ์ด๊ฒ ๋ฐ๋ก instruments ๊ณ์ธต์ ๋ฃจํธ ํด๋์ค์ด๋ค.- instrument์
stored properties(data)๋ฅผ ์ ์ธํ๋๋ฐ, ์ด๋ ๋ชจ๋ instruments๊ฐ ๊ฐ๊ณ ์๋ ๊ฒ์ด๋ค. initํค์๋๋ฅผ ์ฌ์ฉํด์ ํด๋์ค์initializer๋ฅผ ์์ฑํ๋๋ฐ, ์ด๋ ๋ชจ๋stored properties๋ฅผ ์ด๊ธฐํํ์ฌ ์๋ก์ด instruments๋ฅผ ๊ตฌ์ฑํ๊ธฐ ์ํ ๊ฒ์ด๋ค.- instruments์ stored property์ธ brand๋ฅผ parameter๋ก ์ ๋ฌ๋ brand๋ก ์ค์ ํ๋ค. ์ด ๋, property์ parameter์ ์ด๋ฆ์ด ๊ฐ์ผ๋ฏ๋ก,
selfํค์๋๋ฅผ ์ฌ์ฉํ์ฌ ์๋ก ๊ตฌ๋ถํ๋ค.
ใ ค
ใ ค
Methods
์ ๊ธฐ์ ์ข ๋ฅ์ ์๊ด ์์ด ์กฐ์จํ๊ฑฐ๋ ์ฐ์ฃผ๋ฅผ ํ ์ ์๋๋ฐ, Instrument ํด๋์ค ๋ด๋ถ์ ์๋ ์ฝ๋๋ฅผ ์ถ๊ฐํ๋ค.
func tune() -> String { fatalError("Implement this method for \(brand)") }- tune()
method๋ ํธ์ถํ๋ฉด ๋ฐํ์์ ํฌ๋์๊ฐ ๋ฐ์ํ๋ placeholder ํจ์์ด๋ค. - ์ด์ ๊ฐ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ ๋ฉ์๋๋ค์ ์ง์ ์ ์ธ ์ฌ์ฉ์ ์๋ํ์ง ์๊ธฐ ๋๋ฌธ์ ์ถ์์ (
abstract)์ด๋ผ๊ณ ํ๋ค. ๋์ ์, ๋ฉ์๋๋ฅผoverrideํด์ ์ ์ ํ ์์ ์ ์ํํ๋๋ก ํ๋subclass๋ฅผ ์ ์ํด์ผํ๋ค. class๋ด๋ถ์ ์ ์๋ ํจ์๋ค์ Instrument์ brand์ ๊ฐ์ property์ ์ ๊ทผํ ์ ์๊ธฐ ๋๋ฌธ์ ๋ฉ์๋๋ผ๊ณ ํ๋ค.- class์์ property๋ค๊ณผ ๊ด๋ จ ์์
์ ๊ตฌ์ฑํ๋ ๊ฒ์ ๋ณต์ก์ฑ์ ๋ฎ์ถ ์ ์๋ ๊ฐ๋ ฅํ ๋๊ตฌ์ด๋ค. ์ด๋ฅผ ์ฌ์ง์ด
encapsulation๋ผ๊ณ ๋ ํ๋๋ฐ, Class ํ์ ์ ๋ฐ์ดํฐ (ex. stored properties)์ ๋์ (ex. methods)์ ์บก์ํ (encapsulate) ํ๋ค๊ณ ํ๋ค.
ใ ค
ใ ค
์๋ ์ฝ๋๋ฅผ ์ถ๊ฐํ๋ค.
class Music { let notes: [String] init(notes: [String]) { self.notes = notes } func prepared() -> String { return notes.joined(separator: " ") } }- ์ด Music class๋ ๋ฐฐ์ด notes๋ฅผ ์บก์ํํ๊ณ prepared() ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ ๋ฐฐ์ด์ ๋ฌธ์์ด๋ก ๋ณํํ๋ค.
ใ ค
ใ ค
Instrument ํด๋์ค์ tune() ๋ฉ์๋ ๋ค์ ์๋ ์ฝ๋๋ฅผ ์ถ๊ฐํ๋ค.
func play(_ music: Music) -> String { return music.prepared() }- play(_:) ๋ฉ์๋๋ ๋ฌธ์์ด์ ๋ฆฌํดํ๋ค. ์ฌ๊ธฐ์ ๋ฌธ์์ด ๋ฐฐ์ด์ด ์๋ Music ํ์
์ ์ ๋ฌํ ์ด์ ๋, Music ํ์
์ ์์ฑํ๋ ๊ฒ์ด ํ์ ์ปดํ์ผ๋ฌ๊ฐ ํ์ฅ์ ์ํ ์ฅ์๋ฅผ ๋ฐ๋ก ๋ง๋๋ ๊ฒ์ ๊ฐ๋ฅํ๊ฒ ํ๊ธฐ ๋๋ฌธ์ด๋ค.
ใ ค
ใ ค
Instrument ํด๋์ค์ play(_:) ๋ฐ๋ก ๋ค์ ์๋ ์ฝ๋๋ฅผ ์ถ๊ฐํ๋ค.
func perform(_ music: Music) { print(tune()) print(play(music)) }- perform( _ :) ๋ฉ์๋๋ tune() ๋ฉ์๋๋ฅผ ๋จผ์ ํธ์ถํ๊ณ , ์ด์ด์ play(_:) ๋ฉ์๋๋ฅผ ํธ์ถํ๊ณ ์๋ค.
ใ ค
ใ คInheritance
์ ๊ธฐ๋ฅผ ์ถ๊ฐํ๊ธฐ ์ํด์ ์๋ ์ฝ๋๋ฅผ ์ถ๊ฐํ๋ค.
// 1 class Piano: Instrument { let hasPedals: Bool // 2 static let whiteKeys = 52 static let blackKeys = 36 // 3 init(brand: String, hasPedals: Bool = false) { self.hasPedals = hasPedals // 4 super.init(brand: brand) } // 5 override func tune() -> String { return "Piano standard tuning for \(brand)." } override func play(_ music: Music) -> String { // 6 let preparedNotes = super.play(music) return "Piano playing \(preparedNotes)" } }- Piano ํด๋์ค๋ฅผ Instrument ํด๋์ค์
subclass๋ก ์์ฑํ๋ค. Instrument ํด๋์ค๋ Piano ํด๋์ค์parent class๋ผ๊ณ ๋ถ๋ฅธ๋ค. ๋ชจ๋ stored properties์ methods๊ฐ ์๋์ผ๋ก child class์ธ Piano ํด๋์ค๋ก ์์ (inherited) ๋๊ณ , Piano ํด๋์ค ๋ด์์ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค. - ๋ชจ๋ piano๋ค์ ๋ธ๋๋์ ๊ด๊ณ์์ด ์ ํํ ๊ฐ์ ์ซ์์ ํฐ์ ํค์ ๊ฒ์์ ํค๋ฅผ ๊ฐ๊ณ ์๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ด ์์ฑ๊ณผ ๊ด๋ จ๋ ๊ฐ๋ค์ ๋ณํ์ง ์์ผ๋ฏ๋ก
staticํค์๋๋ก ์ ์ธํ๋ค. - ์์ฑ์๋ hasPedals ํ๋ผ๋ฏธํฐ ๊ธฐ๋ณธ๊ฐ์ ์ ๊ณตํ๋๋ฐ, ์ํ๋ค๋ฉด ์ด๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ค.
- child class์ hasPedals ์์ฑ์ ์ค์ ํ ํ์
superํค์๋๋ฅผ ์ฌ์ฉํ์ฌ parent class์ ์ด๋์ ๋ผ์ด์ ๋ฅผ ํธ์ถํ๋ค. super class ์ด๋์ ๋ผ์ด์ ๋ ์์๋ ์์ฑ๋ค์ ์ด๊ธฐํํ๋๋ฐ, ์ฌ๊ธฐ์๋ brand๋ฅผ ์ด๊ธฐํํ๋ค. overrideํค์๋๋ฅผ ์ฌ์ฉํ์ฌ tune ๋ฉ์๋๋ฅผ ์์๋ฐ์์ ์ฌ์ ์ํ๋ค. ์ด๋ parent class์์์ ๊ตฌํ์ฒ๋ผ fatalError()๋ฅผ ํธ์ถํ์ง ์๊ณ , ๋ฌธ์์ด์ ๋ฆฌํดํ๋ค. ์ฆ, ๊ธฐ๋ฅ์ ์ธ ๋ฉด์ผ๋ก ๋งํ์๋ฉด ํผ์๋ ธ์ ํนํ๋ ํ๋์ ํ๋ ์ญํ ๋ก ์ฌ์ ์๋์๋ค.- ์์๋ play(_:) ๋ฉ์๋๋ฅผ ์ฌ์ ์ํ๊ณ , ์ด ๋ฉ์๋ ๋ด๋ถ์์
superํค์๋๋ฅผ ์ฌ์ฉํด์ parent class์ play ๋ฉ์๋๋ฅผ ๋จผ์ ํธ์ถํ๋ค. ๊ทธ๋ฆฌ๊ณ preparedNotes๋ฅผ ์ป์ ํ ์ด๋ฅผ ์ฐ์ฃผํ๋ค๋ ๋ฌธ์์ด๋ก ๋ฆฌํดํ๋ค.
ใ ค
ใ ค
Method Overloading
Piano class์ ์ฌ์ ์๋ play(_:) ๋ฉ์๋ ๋ค์ ์๋ ์ฝ๋๋ฅผ ์ถ๊ฐํ๋ค.
func play(_ music: Music, usingPedals: Bool) -> String { let preparedNotes = super.play(music) if hasPedals && usingPedals { return "Play piano notes \(preparedNotes) with pedals." } else { return "Play piano notes \(preparedNotes) without pedals." } }- play(_:) ๋ฉ์๋๋ usingPedals๊ฐ ์ฐธ์ด๊ณ ์ค์ ๋ก ํผ์๋ ธ๊ฐ ํ๋ฌ์ด ์์ ๋, ํ๋ฌ์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ค๋ฒ๋ก๋ํ๋ค.
- ๋ค๋ฅธ ํ๋ผ๋ฏธํฐ ๋ชฉ๋ก์ ๊ฐ๊ธฐ ๋๋ฌธ์ override ํค์๋๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค. Swift๋ ํ๋ผ๋ฏธํฐ ๋ชฉ๋ก์ ํตํด ์ฌ์ฉํ ๋ฉ์๋๋ฅผ ๊ฒฐ์ ํ๋ค.
- ๋ฉ์๋ ์ด๋ฆ์ด ๊ฐ์์ ํท๊ฐ๋ฆด ์ ์์ผ๋ฏ๋ก ์กฐ์ฌํ ์ฌ์ฉํด์ผํ๋ค.
ใ ค
ใ ค
Piano ํด๋์ค์ play(_:)๋ฅผ ์๋์ ๊ฐ์ด ์์ ํ๋ค.
override func play(_ music: Music) -> String { return play(music, usingPedals: hasPedals) }ใ ค
ใ คInstances
// 1 let piano = Piano(brand: "Yamaha", hasPedals: true) piano.tune() // 2 let music = Music(notes: ["C", "G", "F"]) // 3 piano.play(music) // 4 Piano.whiteKeys Piano.blackKeys- piano ์ธ์คํด์ค ์์ฑ
- music ์ธ์คํด์ค ์์ฑ
- ๊ฐ๋ฅํ๋ค๋ฉด ํญ์ ํ๋ฌ์ ์ฌ์ฉํ๋ Piano ํด๋์ค์ play(_:)๋ฅผ ํธ์ถํ๋ค.
- ํค์ ๊ฐฏ์๋ Piano ํด๋์ค์ ์๋ static ์์์ด๋ฏ๋ก, ํค์ ๊ฐฏ์๋ฅผ ํธ์ถํ๋๋ฐ์ ํน์ ์ธ์คํด์ค๋ ํ์ํ์ง ์๋ค. ๊ทธ์ ํด๋์ค ์ด๋ฆ์ ์ฌ์ฉํ์ฌ ํธ์ถํ๋ฉด ๋๋ค.
ใ ค
ใ ค
Intermediate Abstract Base Classes
class Guitar: Instrument { let stringGauge: String init(brand: String, stringGauge: String = "medium") { self.stringGauge = stringGauge super.init(brand: brand) } }- Instrument์ ๋ง์ฐฌ๊ฐ์ง๋ก, Guitar๋ ํ์ ํด๋์ค์์ tune()๊ณผ play(_:) ๋ฉ์๋๋ฅผ ์ฌ์ ์ํด์ผํ๋ ์ถ์ ํ์
์ผ๋ก ๊ฐ์ฃผ๋๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ์ด๋ Intermediate Abstract Base Class๋ผ๊ณ ๋ ๋ถ๋ฅธ๋ค.
ใ ค
ใ ค
Concrete Guitars
class AcousticGuitar: Guitar { static let numberOfStrings = 6 static let fretCount = 20 override func tune() -> String { return "Tune \(brand) acoustic with E A D G B E" } override func play(_ music: Music) -> String { let preparedNotes = super.play(music) return "Play folk tune on frets \(preparedNotes)." } }- ๋ชจ๋ ์ด์ฟ ์คํฑ ๊ธฐํ๋ค์ 6๊ฐ์ ์ค๊ณผ 20๊ฐ์ ํ๋ ์ ๊ฐ๊ณ ์๋ค. ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ numberOfStrings, fretCount๋
staticํค์๋๋ฅผ ์ด์ฉํ์ฌ ์ ์ธํ๋ค. - ์ด ํด๋์ค์์๋ ์๋ก์ด stored property๊ฐ ์๊ธฐ ๋๋ฌธ์, Guitar๋ก๋ถํฐ ์์ฑ์๋ฅผ ์์๋ฐ์์ ์ฌ์ฉํ๋ฉด ๋๋ฏ๋ก ๋ฐ๋ก ์์ฑ์๋ฅผ ๋ง๋ค ํ์๋ ์๋ค.
ใ ค
ใ ค
Private
// 1 class Amplifier { // 2 private var _volume: Int // 3 private(set) var isOn: Bool init() { isOn = false _volume = 0 } // 4 func plugIn() { isOn = true } func unplug() { isOn = false } // 5 var volume: Int { // 6 get { return isOn ? _volume : 0 } // 7 set { _volume = min(max(newValue, 0), 10) } } }- Amplifier์ ๋ฃจํธ ํด๋์ค์ด๋ค.
- _volume์ private์ผ๋ก ์ ์ธ๋์ด์๋๋ฐ, ์ด๋ ์ธ๋ถ ์ ์ ๋ก๋ถํฐ ์จ๊ฒจ์ ธ์๋ค. ์์ underscore๋ฅผ ๋ถ์ธ ๊ฒ์ private ๊ตฌํ ์ฌํญ์ด๋ผ๋ ๊ฒ์ ๊ฐ์กฐํ๋ ๊ฒ์ด๋ค. convention์ด๊ธฐ ๋๋ฌธ์ ์งํค๋ ๊ฒ์ด ์ข๋ค.
- stored property isOn์ ์ธ๋ถ ์ ์ ๋ค์ด ์ฝ์ ์๋ ์์ง๋ง, ํธ์งํ ์๋ ์๋ค. (Read Only) private(set) ํค์๋๋ฅผ ์ด์ฉํ์ฌ ์ ์ธํ๋ค.
- plugIn()๊ณผ unplug()๋ isOn์ ์ํ์ ์ํฅ์ ๋ฏธ์น๋ค.
computed property์ธ volume์ _volume์ ๊ฐ์ธ๊ณ ์๋ค.getter์์ isOn์ด ๊บผ์ ธ์๋ค๋ฉด ๋ณผ๋ฅจ์ 0์ผ๋ก ์ค์ธ๋ค.setter์์ ๋ณผ๋ฅจ์ ํญ์ 0์์ 10์ฌ์ด์ ๊ฐ์ผ๋ก ๊ณ ์ ๋๋ค.
ใ ค
ใ ค
Polymorphism
๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ์ ๊ฐ์ฅ ํฐ ์ฅ์ ์ค ํ๋๋ ๋ฐ๋ก ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๋์ผํ ์ธํฐํ์ด์ค๋ฅผ ํตํด ์ฌ์ฉํ ์ ์๋ค๋ ๊ฒ์ด๋ค. ์ด๋ฅผ ๋ฐ๋ก ๋คํ์ฑ (Polymorphism)์ด๋ผ๊ณ ํ๋ค.
class Band { let instruments: [Instrument] init(instruments: [Instrument]) { self.instruments = instruments } func perform(_ music: Music) { for instrument in instruments { instrument.perform(music) } } }- Band ํด๋์ค๋ ์ด๋์
๋ผ์ด์ ์์ ์ด๊ธฐํํ instruments ๋ฐฐ์ด์ stored property๋ก ๊ฐ๊ณ ์๋ค. band๋ perform ๋ฉ์๋์์ ๋ฐฐ์ด์ ์๋ ๊ฐ instrument๋ฅผ ๋ชจ๋ ๋๋ฉด์ perform ๋ฉ์๋๋ฅผ ํธ์ถํ๋ค.
ใ ค
ใ ค
let instruments = [piano, acousticGuitar, electricGuitar, bassGuitar] let band = Band(instruments: instruments) band.perform(music)- ๋จผ์ instruments๋ฅผ ์ ์ํ ํ, Band ์ธ์คํด์ค๋ฅผ ์์ฑํ๊ณ instruments ํ๋กํผํฐ๋ฅผ ์ด์ฉํ์ฌ ์ด๊ธฐํํ๋ค.
- ๊ทธ๋ฆฌ๊ณ perform(_:) ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด, ์ค์ Band ๋ด์ instruments๋ [Instrument] ํ์
์ด์ง๋ง, ๊ฐ instrument๋ ๊ฐ๊ฐ์ ํ์
์ ๋ฐ๋ผ ์๋ํ๋ค. ์ด๊ฒ ๋ฐ๋ก ๋คํ์ฑ์ด ์๋ํ๋ ๋ฐฉ์์ด๋ค.
ใ ค
ใ ค
Access Control
Access control์ ๋ค๋ฅธ ์์ค ํ์ผ๊ณผ ๋ชจ๋์ ์๋ ์ฝ๋์์ ์ผ๋ถ ์ฝ๋์ ๋ํ ์ ๊ทผ์ ์ ํํ๋ค. ์ด ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉด ์ฝ๋์ ์ธ๋ถ ๊ตฌํ ์ฌํญ์ ์จ๊ธฐ๊ฑฐ๋ ํด๋น ์ฝ๋์ ์ ๊ทผํ๊ณ ์ฌ์ฉํ ์ ์๋ ๊ธฐ๋ณธ ์ธํฐํ์ด์ค๋ฅผ ์ง์ ํ ์ ์๋ค.
Swift๋ ๋ค์๊ณผ ๊ฐ์ 5๊ฐ์ง ๋ ๋ฒจ์ ์ ๊ทผ ์ ์ด๋ฅผ ์ ๊ณตํ๋ค.
private- ๊ฐ์ ํด๋์ค ๋ด์์๋ง ์ฌ์ฉ ๊ฐ๋ฅ
fileprivate- ๊ฐ์ ์์ค ํ์ผ ๋ด์์ ์ ๊ทผ ๊ฐ๋ฅ (.swift)
internal- ๊ฐ์ ๋ชจ๋์ด๋ ํ๋ก์ ํธ ๋ด์์ ์ ๊ทผ ๊ฐ๋ฅ
public- ๋ชจ๋ ์ธ๋ถ์์๋ ์ ๊ทผ ๊ฐ๋ฅ
open- ๋ชจ๋ ์ธ๋ถ ์ด๋์์๋ ์ฌ์ฉ ๊ฐ๋ฅํ ๋ฟ๋ง ์๋๋ผ, ์ธ๋ถ์์ subclass ๋๋ override๋ ๊ฐ๋ฅ
ใ ค
ใ ค
- ๋ชจ๋ ์ธ๋ถ ์ด๋์์๋ ์ฌ์ฉ ๊ฐ๋ฅํ ๋ฟ๋ง ์๋๋ผ, ์ธ๋ถ์์ subclass ๋๋ override๋ ๊ฐ๋ฅ
์ถ๊ฐ์ ์ผ๋ก final ํค์๋๋ subclass, override๋ ๋ชจ๋ ๋ถ๊ฐ๋ฅํ๋ค. ๋ง์ฝ ํด๋์ค๋ ์์ฑ, ๋ฉ์๋์ ๋ํ ์ ๊ทผ์ ๋ฐ๋ก ์ง์ ํ์ง ์๋๋ค๋ฉด, ๊ธฐ๋ณธ์ ์ผ๋ก internal access๋ก ์ค์ ๋๋ค.
ใ ค
ใ ค'Swift' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Swift] ๋จ๋ฝ ํ๊ฐ (Short-circuit Evaluation), Side Effect (0) 2022.01.20 [Swift] zip(_:_:) (0) 2022.01.14 [Swift] ์ด๋ฆ ์ ์ ๊ท์น (Naming Convention) (0) 2022.01.13 [Swift] Control Transfer Statements (break, continue) (์ ์ด ์ ๋ฌ๋ฌธ) (0) 2022.01.12 [Swift] Loop Statements (for-in, while) (๋ฐ๋ณต๋ฌธ) (0) 2022.01.11