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 |