Deep_Dev
article thumbnail

 

 

 

ν”„λ‘œν† μ½œ 지ν–₯ ν”„λ‘œκ·Έλž˜λ°

Protocol - Oriented Programming 

 

ν”„λ‘œν† μ½œ 지ν–₯ ν”„λ‘œκ·Έλž˜λ° 

ν”νžˆ μ•Œκ³  μžˆλŠ” 객체 지ν–₯ ν”„λ‘œκ·Έλž˜λ° : 사물을 객체둜 ν˜•μ„±ν•˜μ—¬ 곡톡점을 κ°–λŠ” λͺ¨λ“  κ³³μ—μ„œ μƒμ†λ°›λŠ” 객체 λ‚΄λΆ€μ˜ λͺ¨λ“  λ‘œμ§μ„ μΊ‘μŠν™”ν•œλ‹€. μ˜λ„ ν•˜μ§€ μ•Šμ•„λ„ μƒμ†ν–ˆλ‹€λŠ” 이유둜 λͺ¨λ“  속성과 ν–‰μœ„λ₯Ό κ³΅μœ ν•΄μ•Όν•˜λ©°, λ³΅μž‘ν•œ 상속 ꡬ쑰λ₯Ό μ§€λ‹Œ 클래슀λ₯Ό μƒμ†ν–ˆλ‹€λ©΄ μ›ν•˜λŠ” 클래슀λ₯Ό μ°Έμ‘°ν•΄μ•Ό ν•  λ•Œ λ‹€μš΄μΊμŠ€νŒ…μ„ ν•΄μ•Ό ν•œλ‹€. λ˜ν•œ 큰 단점은 단 ν•˜λ‚˜μ˜ SuperClass만 상속할 수 μžˆλ‹€λŠ” 점이닀. μ‹œκ°„μ΄ 흐λ₯΄λ©΄ κΈ°λŠ₯도 ν™•μž₯ν•˜κΈ° λ§ˆλ ¨μ΄λ―€λ‘œ λ³΅μž‘λ„λ„ 높아지고 관리도 μ–΄λ €μ›Œμ§„λ‹€.

 

ν”„λ‘œν† μ½œ 지ν–₯ ν”„λ‘œκ·Έλž˜λ° : ν•„μš”ν•œ λΆ€λΆ„λ§Œ ν”„λ‘œν† μ½œλ‘œ λΆ„λ¦¬ν•΄μ„œ λ§Œλ“€ 수 있고 닀쀑 ν”„λ‘œν† μ½œμ„ κ΅¬ν˜„ν•  수 μžˆλ‹€. κ²Œλ‹€κ°€ ν”„λ‘œν† μ½œ κ·œμΉ™μ„ class, struct, enum에 μ μš©ν•  수 있기 λ•Œλ¬Έμ— ν™•μž₯ λΆ€λΆ„μ—μ„œλ„ μœ μ—°ν•˜λ‹€. μŠ€μœ„ν”„νŠΈλŠ” λ‹€λ₯Έ 언어와 달리 클래슀둜 κ΅¬ν˜„λœ νƒ€μž…λ³΄λ‹€λŠ” λŒ€λΆ€λΆ„ ꡬ쑰체둜 κΈ°λ³Έ νƒ€μž…μ΄ κ΅¬ν˜„λ˜μ–΄ μžˆλ‹€. 상속도 λ˜μ§€ μ•ŠλŠ” 곡톡 κΈ°λŠ₯을 κ°€μ§ˆ 수 μžˆλŠ” λ°©λ²•μ—λŠ” ν”„λ‘œν† μ½œκ³Ό μ΅μŠ€ν…μ…˜μ΄ μžˆλ‹€.

 

 

 ν”„λ‘œν† μ½œ κ΅¬ν˜„

protocol Walkable {
     var isBarFoot: Bool { get set }
     
     func walk()
}

struct Person: Walkable {
     var isBareFoot: Bool
     var name: String
     
     func walk() {
          print("\(name)은 κ±·μŠ΅λ‹ˆλ‹€")
     }
}

struct Animal: Walkable {
     var isBareFoot: Bool
     
     func walk() {
          print("\name)은 κ±·μŠ΅λ‹ˆλ‹€")
     }
}

μ—¬κΈ° Walkable ν”„λ‘œν† μ½œμ΄ μžˆλ‹€. 이 ν”„λ‘œν† μ½œμ€ λ§¨λ°œμΈμ§€ μ•„λ‹Œμ§€μ˜ ꡬ뢄과 걸을 수 있λŠ₯이 μžˆλ‹€.

 

ν”„λ‘œν† μ½œ μ±„νƒμ‹œ ν”„λ‘œν† μ½œμ΄ μš”κ΅¬ν•˜λŠ” 사항을 λͺ¨λ‘ κ΅¬ν˜„ν•΄μ£Όμ–΄μ•Ό ν•œλ‹€. 

 

예λ₯Ό λ“€μ–΄, ν”„λ‘œν† μ½œμ— λ§Žμ€ μš”κ΅¬μ‚¬ν•­μ΄ λ“€μ–΄μžˆκ³  λ§Žμ€ κ΅¬μ‘°μ²΄μ—μ„œ 채택을 ν–ˆλ‹€λ©΄ λ§Žμ€ μ€‘λ³΅λœ μ½”λ“œλ₯Ό μ‚¬μš©ν•΄μ•Ό ν•  것이닀. 

이λ₯Ό λ°©μ§€ν•˜κΈ° μœ„ν•΄ ν”„λ‘œν† μ½œμ˜ μš”κ΅¬μ‚¬ν•­μ„ κ΅¬ν˜„ν•˜μ§€ μ•Šλ”λΌλ„ ν”„λ‘œν† μ½œμ˜ μ΅μŠ€ν…μ…˜μ— 미리 ν”„λ‘œν† μ½œμ˜ μš”κ΅¬μ‚¬ν•­μ„ κ΅¬ν˜„ν•΄ λ‘˜ 수 μžˆλ‹€.

protocol Walkable {
     var isBareFoot: Bool { get set }
     var speed: Double { get set }
     
     func walk(name: String)
}

extension Walkable {
     func walk(name: String) {
          if isBareFoot == true {
               print("\(name)은 맨발인 μƒνƒœμ— \(speed)μ†λ„λ‘œ κ±·μŠ΅λ‹ˆλ‹€.")
          } else {
               print("\(name)은 μ‹ λ°œμΈ μƒνƒœμ— \(speed)μ†λ„λ‘œ κ±·μŠ΅λ‹ˆλ‹€.")
          }
     }
}

struct Person: Walkable {
     var isBareFoot: Bool
     var speed: Double
}

struct Animal: Walkable {
     var isBareFoot: Bool
     var speed: Double
}

let gilDong = Person(isBareFoot: false, speed: 5.0)
gilDong.walk(name:"길동")

let cat = Animal(isBareFoot: true, speed: 10.0)
cat.walk(name:"μ•Όμ˜Ή")

 

μœ„ μ½”λ“œμ—μ„œ Personκ³Ό Animal은 Walkable의 μš”κ΅¬μ‚¬ν•­μΈ walk(name:)을 κ΅¬ν˜„ν•˜μ§€ μ•Šμ•˜μŒμ—λ„ λΆˆκ΅¬ν•˜κ³  였λ₯˜κ°€ λ°œμƒν•˜μ§€ μ•ŠλŠ”λ‹€.

 

ν”„λ‘œν† μ½œμ΄ μš”κ΅¬ν•˜λŠ” 사항을 미리 κ΅¬ν˜„ν•΄ λ‘˜ 수 μžˆλ‹€λ©΄ μ€‘λ³΅λœ μ½”λ“œλ₯Ό ν”Όν•  수 μžˆλ‹€. κ΅¬ν˜„μ„ μž˜ν•΄λ‘”λ‹€λ©΄ ν”„λ‘œν† μ½œ μ±„νƒλ§ŒμœΌλ‘œλ„ κ·Έ νƒ€μž…μ˜ κΈ°λŠ₯이 μΆ”κ°€λ˜μ–΄ μ‚¬μš©ν•  수 μžˆλŠ” 것이닀.

protocol Walkable {
     func walk()
}

extension Walkable {
     func walk() {
          print("κ±·λ‹€")
     }
}

protocol Flyable {
     func fly()
}

extension Flyable {
     func fly() {
          print("λ‚ λ‹€")
     }
}

protocol Runable {
     func run()
}

extension Runable {
	 func run() {
          print("λ›°λ‹€")
     }
}

struct Person: Walkable, Runable {}

let gilDong = Person()
gilDong.walk()

struct Bird: Flyable, Walkable, Runable {}

let bird = Bird()
bird.fly()
bird.walk()
bird.run()

 

ν¬λ‘œν† μ½œ μ±„νƒλ§ŒμœΌλ‘œλ„ κ·Έ κΈ°λŠ₯을 μ‚¬μš©ν•  수 있게 ν”„λ‘œν† μ½œ κ΅¬ν˜„μ„ 잘 ν•΄λ‘λŠ”κ²Œ ν”„λ‘œν† μ½œ 지ν–₯ ν”„λ‘œκ·Έλž˜λ°μ—μ„œ κ°€μž₯ μ€‘μš”ν•˜λ‹€.

λ˜ν•œ 객체 지ν–₯ ν”„λ‘œκ·Έλž˜λ°μ˜ SuperClass와 달리, κΈ°λŠ₯듀을 λΆ„λ¦¬ν•˜μ—¬, Protocol extension을 생성할 수 μžˆλ‹€. μ΄λŠ” SuperClass 단일화 λ¬Έμ œμ μ— λŒ€ν•œ 해결책이라고 λ³Ό 수 μžˆλ‹€.

 

 


쑰금 더 μžμ„Ένžˆ λ“€μ—¬λ‹€λ³΄μž

βœ… Protocol Oriented Programming 탄생배경

일반적으둜 OOPμ—μ„œ 클래슀의 상속 κ°œλ…μ„ 톡해 곡톡 κΈ°λŠ₯듀을 λͺ¨λ“ˆν™”ν•˜μ—¬ μ‚¬μš©ν•  수 μžˆμ—ˆμœΌλ‚˜, ꡬ쑰체 ν˜Ήμ€ μ—΄κ±°ν˜•μ˜ κ²½μš°μ—λŠ” 상속이 λΆˆκ°€ν•˜κΈ°μ— 같은 νƒ€μž…μ— λŒ€ν•΄μ„œ 곡톡적인 κΈ°λŠ₯ κ΅¬ν˜„μ„ μœ„ν•΄μ„œλŠ” λ‹€λ₯Έ 방법을 μ΄μš©ν•΄μ•Ό ν–ˆλ‹€.

 

이λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•œ λ°©μ•ˆμ΄ Appe WWDC15( Swift 2 )μ—μ„œ Extension이 λ°œν‘œλ˜μ—ˆλ‹€.

Protocol ( 청사진 ) 을 κ΅¬ν˜„ν•˜κ³  Extension으둜 ν•΄λ‹Ή ν”„λ‘œν† μ½œμ˜ κΈ°λŠ₯을 ν™•μž₯ν•˜λŠ” ν˜•νƒœλ‘œ μ‚¬μš©ν•œλ‹€.

이λ₯Ό ν”„λ‘œν† μ½œ μ΄ˆκΈ°κ΅¬ν˜„ ( Protocol Default Implementation ) 이라고 ν•œλ‹€. 

 

 

βœ… POP의 μž₯점

  • μ½”λ“œμ˜ 쀑볡을 μ΅œμ†Œν™”
  • 가볍고 μ•ˆμ „ν•˜λ‹€.
    • 상속과 달리 ν•„μš”ν•œ κ²ƒλ§Œ κ³¨λΌμ„œ μ‚¬μš©ν•  수 μžˆλ‹€.
    • μƒμ†μ˜ 경우, μ°Έμ‘°νƒ€μž…μ΄λ―€λ‘œ μ°Έμ‘° 좔적을 μœ„ν•œ λΉ„μš©μ΄ 많이 λ°œμƒν•˜κΈ° λ•Œλ¬Έμ— μ†λ„λ©΄μ—μ„œλŠ” λ‹€μ†Œ λŠλ¦¬λ‹€.
  • κ°’ νƒ€μž…μ˜ 상속 효과
    • κ³΅ν†΅λœ κΈ°λŠ₯을 μ‰½κ²Œ κ΅¬ν˜„ν•  수 μžˆλ‹€.
  • μˆ˜ν‰μ μΈ ν™•μž₯ κΈ°λŠ₯
  • μ œλ„€λ¦­μ˜ ν™œμš©

βœ… ν”„λ‘œν† μ½œ ( Protocol )

ν”„λ‘œν† μ½œμ€ νŠΉμ • κΈ°λŠ₯ μˆ˜ν–‰μ— ν•„μˆ˜μ μΈ μš”μ†Œλ₯Ό μ •μ˜ν•œ 청사진(blueprint)이닀.
ν”„λ‘œν† μ½œμ„ λ§Œμ‘±μ‹œν‚€λŠ” νƒ€μž…μ„ ν”„λ‘œν† μ½œμ„ λ”°λ₯Έλ‹€(conform)κ³  λ§ν•œλ‹€.
ν”„λ‘œν† μ½œμ— ν•„μˆ˜ κ΅¬ν˜„μ„ μΆ”κ°€ν•˜κ±°λ‚˜ 좔가적인 κΈ°λŠ₯을 λ”ν•˜κΈ° μœ„ν•΄ ν”„λ‘œν† μ½œμ„ ν™•μž₯(extend) ν•˜λŠ”κ²ƒμ΄ κ°€λŠ₯ν•˜λ‹€. 

 

 

βœ… ν”„λ‘œν† μ½œ 문법

protocol SomeProtocol {
     // protocol definition goes here
}

 

βœ… ν”„λ‘œνΌν‹° μš”κ΅¬μ‚¬ν•­

protocol SomeProtocol {
     var mustBeSettle: Int { get set }
     var doesNotToBeSettable: Int { get }
}

ν”„λ‘œν† μ½œμ—μ„œλŠ” ν”„λ‘œνΌν‹°μ˜ νƒ€μž… 그리고 gettable, settable을 λͺ…μ‹œν•œλ‹€. 

ν•„μˆ˜ ν”„λ‘œνΌν‹°λŠ” 항상 var둜 μ„ μ–Έν•΄μ•Όν•œλ‹€.

 

protocol AnotherProtocol {
     static var someTypeProperty: Int { get set }
}

νƒ€μž… ν”„λ‘œνΌν‹°λŠ” static ν‚€μ›Œλ“œλ₯Ό 적어 μ„ μ–Έν•œλ‹€. 

 

βœ… λ©”μ†Œλ“œ μš”κ΅¬μ‚¬ν•­

protocol someProtocol {
     static var someTypeMethod()
}

ν•„μˆ˜ λ©”μ†Œλ“œ μ§€μ •μ‹œ ν•¨μˆ˜λͺ…κ³Ό λ°˜ν™˜κ°’μ„ 지정할 수 있고, κ΅¬ν˜„μ— μ‚¬μš©ν•˜λŠ” κ΄„ν˜ΈλŠ” 적지 μ•Šμ•„λ„ λœλ‹€.

 

 

βœ… ν”„λ‘œν† μ½œ 초기 κ΅¬ν˜„ ( Protocol Default Implementation )

extension으둜 protocol에 μ •μ˜λœ 것듀을 미리 κ΅¬ν˜„ν•¨μœΌλ‘œμ„œ ν•΄λ‹Ή protocl을 κ΅¬ν˜„ν•˜λŠ” λŒ€μƒλ“€μ΄ μ½”λ“œμ˜ 쀑볡을 ν”Όν•  수 μžˆλ‹€.

// ν”„λ‘œν† μ½œ μ •μ˜
protocol Person {
     var name: String? { get }
     var age: Int? { get }
     
     func getName() -> String?
     func getAge() -> Int?
}

// ν”„λ‘œν† μ½œ κΈ°λŠ₯ ν™•μž₯
extension Person {
	func getName() -> String? {
         return self.name
    }
    
    func getAge() -> Int? {
         return self.age
    }
}

 

μœ„ μ„€λͺ…λŒ€λ‘œ protoclμ—λŠ” μ„ μ–ΈλΆ€(μ •μ˜)만 적어주고 ν•΄λ‹Ή κΈ°λŠ₯을 ν™•μž₯(extension) ν•΄μ£Όμ—ˆλ‹€.

 

struct Student: Person {
     var name: String?
     var age: Int?
     
     init(name: String?, age: Int?) {
          self.name = name
          self.age = age
     }
}

 

μ΄μ–΄μ„œ Student ꡬ쑰체가 Person ν”„λ‘œν† μ½œμ„ 채택(μ€€μˆ˜) ν•œλ‹€.

let gilDong = Student(name: "gilDong", age: 25)
print(gilDong.getName()) // gilDong

Stduent ꡬ쑰체λ₯Ό μ΄ˆκΈ°ν™”ν•˜κ³ , .(dot)문법을 톡해 getName λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜λ©΄ 이름이 좜λ ₯λœλ‹€.