๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐Ÿ“ ๊ธฐ๋ก/TIL

[TIL] 20231129

Protocol์„ ํ™œ์šฉํ•œ ์ถ”์ƒํ™” (์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง)

์ด๋ฒˆ์ฃผ ์ƒˆ์‹น ๊ณผ์ œ์—์„œ PR์„ ์˜ฌ๋ฆฐ ํ›„์— ์•„์ด๋””์–ด๊ฐ€ ๋– ์˜ฌ๋ผ ์–ด์ œ ํ”„๋กœํ† ์ฝœ ๋” ์ž˜์“ฐ๊ธฐ!! ์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ์–ด์ œ ์ •๋ฆฌํ–ˆ๋Š”๋ฐ, ํ•ด๋‹น ๋‚ด์šฉ์„ ์ ์šฉํ•ด์„œ ์˜ค๋Š˜ ์ฝ”๋“œ ๋ฆฌํŒฉํ† ๋ง์„ ํ•ด๋ดค๋‹ค.

์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ

protocol extension ์„ ํ™œ์šฉํ•œ ๋ฉ”์„œ๋“œ ๊ธฐ๋ณธ ๊ตฌํ˜„

Playable ํ”„๋กœํ† ์ฝœ extension์„ ํ†ตํ•ด ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๊ธฐ๋ณธ ๊ตฌํ˜„ํ•ด ์ถ”์ƒํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • validateUserInput() - ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๊ฐ’ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๋ฉ”์„œ๋“œ
    • ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๊ฐ’ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๋กœ์ง์˜ ๊ฒฝ์šฐ ๊ฐ€์œ„๋ฐ”์œ„๋ณด, ๋ฌต์ฐŒ๋น  ๋‘ ๊ฒŒ์ž„์—์„œ ๋™์ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— extension์— ๊ธฐ๋ณธ ๊ตฌํ˜„ํ•จ์œผ๋กœ์จ ๊ฐ ํด๋ž˜์Šค ๋‚ด์—์„œ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•„๋„ ๋˜๋„๋ก ํ•ด์„œ ์ค‘๋ณต๋œ ์ฝ”๋“œ๋ฅผ ํ•˜๋‚˜๋กœ ๋ฌถ์—ˆ์Šต๋‹ˆ๋‹ค.
  • judgeWinner() - ๊ฒŒ์ž„์˜ ์Šน์ž๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ๋ฉ”์„œ๋“œ
    • ๊ฒŒ์ž„์˜ ์Šน์ž๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ๋กœ์ง์ด ๋ฌต์ฐŒ๋น  ํด๋ž˜์Šค์—์„œ ๋ฐ˜๋ณต๋˜์–ด ๋ฉ”์„œ๋“œํ™” ํ•ด์ฃผ์—ˆ๊ณ , ๊ธฐ๋ณธ ๊ตฌํ˜„์„ ํ†ตํ•ด ํด๋ž˜์Šค ๋‚ด ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ํ†ตํ•ด ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.
    • ์ด ๋ฉ”์„œ๋“œ์˜ ๊ฒฝ์šฐ ์Šน์ž๋ฅผ ํŒ๋‹จํ•˜๋Š” ๋กœ์ง์ด ๋‘ ๊ฒŒ์ž„์—์„œ ๋™์ผํ•˜๊ธด ํ•˜์ง€๋งŒ, ํ˜„์žฌ๋Š” ๋ฌต์ฐŒ๋น  ํด๋ž˜์Šค์—์„œ๋งŒ ์‚ฌ์šฉ๋˜์–ด ํ•ด๋‹น ํ•จ์ˆ˜์˜ ์œ„์น˜๋ฅผ ๋ฌต์ฐŒ๋น  ํด๋ž˜์Šค๋กœ ์˜ฎ๊ฒจ๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. (ํ™•์žฅ์„ฑ์„ ๋Œ€๋น„ํ•œ๋‹ค๋ฉด ํ”„๋กœํ† ์ฝœ ์ต์Šคํ…์…˜ ๋‚ด ๊ธฐ๋ณธ๊ตฌํ˜„์ด ๋” ์ข‹์„ ๊ฒƒ ๊ฐ™๊ธฐ๋„ ํ•จ)

<๊ธฐ์กด ์ฝ”๋“œ>

// ๊ฐ€์œ„๋ฐ”์œ„๋ณด ํด๋ž˜์Šค
final class RockPaperScissorsManager: Playable {

    func validateUserInput(_ input: String?) throws -> RockPaperScissorsType {
        guard let input else {
            throw RockPaperScissorsError.invalidInput
        }

        switch input {
        case "0": return .none
        case "1": return .scissors
        case "2": return .rock
        case "3": return .paper
        default: throw RockPaperScissorsError.invalidInput
        }
    }
}

// ๋ฌต์ฐŒ๋น  ํด๋ž˜์Šค
final class AdvancedRockPaperScissorsManager: Playable {

    func validateUserInput(_ input: String?) throws -> RockPaperScissorsType {
        guard let input else {
            throw GameError.invalidInput
        }

        switch input {
        case "0": return .none
        case "1": return .rock
        case "2": return .scissors
        case "3": return .paper
        default: throw GameError.invalidInput
        }
    }
}

 

๋‘ ํด๋ž˜์Šค ๋‚ด ํ•จ์ˆ˜๊ฐ€ ๊ต‰์žฅํžˆ ๋น„์Šทํ•˜๋‹ค.. ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๊ฐ’์ธ 1, 2, 3 ์ด ์˜๋ฏธํ•˜๋Š”๊ฒŒ ๋‹ฌ๋ผ์„œ ํŠน์ • ์ผ€์ด์Šค์—์„œ ๋ฆฌํ„ดํ•˜๋Š” ์ผ€์ด์Šค๋งŒ ์กฐ๊ธˆ ๋‹ค๋ฆ„!!!

๊ทธ๋Ÿฐ๋ฐ ์ด๊ฑธ ๋‘ ๋ฒˆ ๊ตฌํ˜„ํ•ด?!??!!??! ์ƒ๊ฐ์ด ๋“ค์—ˆ์Œ

protocol extension ๋‚ด ๊ธฐ๋ณธ ๊ตฌํ˜„์„ ํ†ตํ•ด ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ๋‹ค!

 

extension Playable {

    func validateUserInput(_ input: String?) throws -> Int {
        guard let input = input,
              let num = Int(input),
              (0...3).contains(num) else {
            throw GameError.invalidInput
        }

        return num
    }

    func judgeWinner(_ gameResult: GameResultType) -> PlayerType {
        return gameResult == .win ? .user : .computer
    }
}

 

์ด๋ ‡๊ฒŒ ๊ตฌํ˜„ํ•ด๋‘๋ฉด ๊ฐ ํด๋ž˜์Šค ๋‚ด์—์„œ ๋”ฐ๋กœ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•„๋„ ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ํ•˜๋ฉด ์ด๋ ‡๊ฒŒ ๊ธฐ๋ณธ ๊ตฌํ˜„ํ•ด๋‘” ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.

ํ”„๋กœํ† ์ฝœ ์ต์Šคํ…์…˜ ๋‚ด ๊ธฐ๋ณธ ๊ตฌํ˜„์„ ํ†ตํ•ด ๊ณตํ†ต๋œ ๋ถ€๋ถ„์„ ๋ฌถ์–ด ์ถ”์ƒํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ!!!

์Šน์ž ํŒ๋‹จ ๋กœ์ง๋„ ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ์ข€ ๋ฐ˜๋ณต๋˜๊ธธ๋ž˜ ๊ทธ๋ƒฅ ๋ฉ”์„œ๋“œํ™” ์‹œ์ผœ์„œ ์–˜๋„ extension ๋‚ด์— ์ •์˜ํ•ด์คฌ๋‹ค.

PR ์ฝ”๋ฉ˜ํŠธ์— ๋‚จ๊ฒผ๋“ฏ์ด ์ง€๊ธˆ์€ ํ•œ ํด๋ž˜์Šค์—์„œ๋งŒ ์‚ฌ์šฉ๋˜์–ด์„œ ๊ตณ์ด ์—ฌ๊ธฐ๋‹ค๊ฐ€ ๊ตฌํ˜„์•ˆํ•˜๊ตฌ ์‚ฌ์šฉํ•˜๋Š” ํด๋ž˜์Šค์—๋งŒ ๊ตฌํ˜„ํ•ด๋„ ๋  ๊ฒƒ ๊ฐ™๋‹ค ใ…Ž…. ํ™•์žฅ์„ฑ์„ ์œ„ํ•ด ์–ด์ฉŒ๊ตฌ…์ด๋ ‡๊ฒŒ ์ ๊ธด ํ–ˆ์ง€๋งŒ.. ใ…Ž…ใ…Ž…

associatedtype ํ™œ์šฉ

ํ”„๋กœํ† ์ฝœ ๋‚ด์—์„œ ์ œ๋„ค๋ฆญ์˜ ์—ญํ• ์„ ํ•˜๋Š” associatedtype์„ ํ™œ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

  • judgeGame() ํ•จ์ˆ˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜๊ฒจ์ฃผ๋Š” ํƒ€์ž…(๋ฌต์ฐŒ๋น  ํƒ€์ž…, ๊ฐ€์œ„๋ฐ”์œ„๋ณด ํƒ€์ž…)์„ ๊ฐ ํด๋ž˜์Šค์—์„œ ๋‹ค๋ฅด๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด associatedtype์„ ํ™œ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. (๋‹คํ˜•์„ฑ ์ธก๋ฉด์—์„œ์˜ ์žฅ์ ์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•จ)
  • ๊ธฐ์กด์—๋Š” RockPaperScissorsType ์„ ์žฌํ™œ์šฉํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ–ˆ์ง€๋งŒ ์ง๊ด€์ ์ธ ์ฝ”๋“œ๋ฅผ ์œ„ํ•ด AdvancedRockPaperScissorsType ์„ ์ƒ์„ฑํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
  • ๋‘ ๊ฐœ์˜ ํƒ€์ž…(RockPaperScissorsType, AdvancedRockPaperScissorsType)์˜ ๊ตฌ์กฐ๊ฐ€ ๊ฐ™์•„ ๊ธฐ์กด ์ฝ”๋“œ๋„ ๋กœ์ง์ƒ ๋ฌธ์ œ๋Š” ์—†์—ˆ์ง€๋งŒ, ๊ฐ ํด๋ž˜์Šค์— ํ•ด๋‹นํ•˜๋Š” ํƒ€์ž…์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด ์—ญํ• ์„ ๋ช…ํ™•ํžˆ ํ•˜๊ณ  ์ฝ”๋“œ ๊ฐ€๋…์„ฑ์„ ๋†’์˜€์Šต๋‹ˆ๋‹ค.
// ๊ธฐ์กด ์ฝ”๋“œ ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž… RockPaperScissorsType -> AdvancedRockPaperScissorsType ๋ณ€๊ฒฝ
func judgeGame(user: AdvancedRockPaperScissorsType?,
                   computer: AdvancedRockPaperScissorsType?,
                   turn: PlayerType) -> GameResultType {
        if user == AdvancedRockPaperScissorsType.none {
            return .exit
        }

        if user != computer {
            return .draw
        }

        return turn == .user ? .win : .lose
    }
}

 

PR ์ฝ”๋ฉ˜ํŠธ์— ์จ๋‘” ๊ฒƒ ์ฒ˜๋Ÿผ ํŒ๋‹จ ๋กœ์ง์ƒ์—๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์ง€๋งŒ ์‚ฌ์‹ค ๋ฌต์ฐŒ๋น  ํด๋ž˜์Šค์—์„œ๋Š” ๋ฌต์ฐŒ๋น  ํƒ€์ž…์œผ๋กœ ํŒ๋ณ„์„ ํ•ด์ฃผ๋Š”๊ฒŒ ๋งž์ง€ ์•Š๋‚˜?!?!?

๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์–ด associatedtype์„ ํ™œ์šฉํ•จ!!! ๊ฐ€์œ„๋ฐ”์œ„๋ณด ํด๋ž˜์Šค์—์„œ๋Š” ๊ฐ€์œ„๋ฐ”์œ„๋ณด ํƒ€์ž…์œผ๋กœ ํŒ๋ณ„ํ•˜๊ณ , ๋ฌต์ฐŒ๋น  ํด๋ž˜์Šค์—์„œ๋Š” ๋ฌต์ฐŒ๋น  ํƒ€์ž…์œผ๋กœ ํŒ๋ณ„ํ•ด์„œ ๋” ์ง๊ด€์ ์ธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ , ํด๋ž˜์Šค๋ณ„ ์—ญํ• ์„ ๋ช…ํ™•ํžˆ ํ–ˆ๋‹ค.

ํƒ€์ž… ๋ณ€ํ™˜์„ ์œ„ํ•œ Convertible ํ”„๋กœํ† ์ฝœ ์ƒ์„ฑ

  • ๋ฌต์ฐŒ๋น  ๊ฒŒ์ž„ ๋‚ด์—์„œ ํŒจ๊ฐ€ ๋‹ค๋ฅผ ๊ฒฝ์šฐ ๊ฐ€์œ„๋ฐ”์œ„๋ณด ๊ฒŒ์ž„์˜ ๊ฒฐ๊ณผ๋กœ ํŒ๋‹จํ•ด์ฃผ์–ด์•ผ ํ•˜๋Š” ๋กœ์ง์ด ์žˆ์–ด์„œ ๊ฐ€์œ„๋ฐ”์œ„๋ณด.judgeGame() ์„ ํ˜ธ์ถœํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์ด๋•Œ ๋ฌต์ฐŒ๋น  enum ํƒ€์ž…์˜ ๊ฐ’์„ ๊ฐ€์œ„๋ฐ”์œ„๋ณด enum ํƒ€์ž…์œผ๋กœ ๋ฐ”๊ฟ”์„œ ๋„˜๊ฒจ์ฃผ๊ธฐ ์œ„ํ•œ ๋ณ€ํ™˜ ๋กœ์ง์—์„œ Convertible ํ”„๋กœํ† ์ฝœ์„ ํ™œ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ํ™•์žฅ์„ฑ์„ ์œ„ํ•ด Convertible ํ”„๋กœํ† ์ฝœ ๋‚ด์—์„œ๋„ type ๋ถ€๋ถ„์„ associatedtype์œผ๋กœ ์„ ์–ธํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

<๊ธฐ์กด ์ฝ”๋“œ>

@frozen
enum RockPaperScissorsType: Int {
    case none = 0
    case scissors = 1
    case rock = 2
    case paper = 3

    func getAdvancedType() -> RockPaperScissorsType {
        switch self {
        case .none:
            return .none
        case .scissors:
            return .rock
        case .rock:
            return .scissors
        case .paper:
            return .paper
        }
    }
}

 

<๋ณ€๊ฒฝํ•œ ์ฝ”๋“œ>

protocol Convertible {
    associatedtype T
    
    var convertedType: T { get }
}

enum AdvancedRockPaperScissorsType: Int, Convertible {
    case none = 0
    case rock = 1
    case scissors = 2
    case paper = 3
    
    typealias T = RockPaperScissorsType
    
    var convertedType: T {
        switch self {
        case .none:
            return .none
        case .rock:
            return .rock
        case .scissors:
            return .scissors
        case .paper:
            return .paper
        }
    }
}

 

๊ธฐ์กด ์ฝ”๋“œ๋ž‘ ๋”ฑํžˆ ๋ฐ”๋€๊ฒŒ ์—†๋‹ค? ๋ผ๊ณ  ๋Š๋‚„ ์ˆ˜ ์žˆ๋Š”๋ฐ,,,

๊ฐ ์ผ€์ด์Šค์— ๋งค์นญ๋˜๋Š” ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ฐ”๋€Œ์–ด์„œ ์กฐ๊ธˆ ๋” ๊ฐœ์„ ๋œ ๊ฒƒ ๊ฐ™๊ธดํ•˜๋‹ค..

๋ฆฌ๋ทฐ์— ISP์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ์–ธ๊ธ‰ํ•ด์ฃผ์…จ๋Š”๋ฐ ๋ฆฌ๋ทฐ์–ด๋‹˜ ์˜๊ฒฌ์— ์™„์ „ ๋™์˜ํ•ด์„œ ์†”๋ฆฌ๋“œ ์ œ๋Œ€๋กœ ์ •๋ฆฌํ•ด๋ด์•ผ๊ฒ ๋‹ค!!!!

'๐Ÿ“ ๊ธฐ๋ก > TIL' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[TIL] 20231204  (1) 2023.12.04
[TIL] 20231130  (2) 2023.11.30
[TIL] 20231128  (3) 2023.11.29
[TIL] 20231124  (1) 2023.11.25
[TIL] 20231123  (1) 2023.11.23