suvera-dev ๐Ÿฅฆ

Swift) SOLID ์›์น™ in Swift ๋ณธ๋ฌธ

Language/Swift

Swift) SOLID ์›์น™ in Swift

suvera 2022. 4. 14. 22:06

SOLID ์›์น™์ด๋ž€ ? 

 

SOLID ์›์น™์ด๋ž€ ๊ฐ์ฒด์ง€ํ–ฅ ์„ค๊ณ„์— ๋” ์ข‹์€ ์•„ํ‚คํ…์ณ๋ฅผ ์„ค๊ณ„ํ•˜๊ธฐ ์œ„ํ•ด

์ง€์ผœ์•ผํ•˜๋Š” ์›์น™๋“ค์˜ 5๊ฐ€์ง€๋ฅผ ์•ž์˜ ์•ฝ์–ด๋งŒ ๋”ฐ์„œ ์ •๋ฆฌํ•œ ๋‹จ์–ด์ž…๋‹ˆ๋‹ค. 

 

 

SOLID ์›์น™์„ ์™œ ์•Œ์•„์•ผํ•˜์ฃ  ? 

 

๊ฐœ๋ฐœ์„ ํ•  ๋•Œ ๋‹น์žฅ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ๋„ ์ค‘์š”ํ•˜์ง€๋งŒ,

์ƒˆ๋กญ๊ฒŒ ์–ด๋–ค ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋˜๊ฑฐ๋‚˜ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ํ•„์š”ํ•  ๋•Œ

๋”์šฑ ์ƒ์‚ฐ์„ฑ ์žˆ๊ณ  ์œ ์—ฐํ•˜๊ฒŒ ๋Œ€์ฒ˜๊ฐ€ ๊ฐ€๋Šฅํ•ด์•ผ ์ข‹๊ฒ ์ฃ .?

 

์ด๋Ÿฌํ•œ ์ข‹์€ ์„ค๊ณ„๋ฅผ ์œ„ํ•œ ์ตœ์†Œํ•œ์˜ ์›์น™๋“ค์„ ์ •๋ฆฌํ•œ๊ฒŒ SOLID ์›์น™์ด๋ผ๊ณ  

ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ์š”.  VIPER๋‚˜ MVVM๋„ ๋ชจ๋‘ ์ด๋Ÿฐ ์›์น™์— ์ž…๊ฐํ•ด์„œ ๋งŒ๋“ค์–ด์กŒ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

 

 

SOLID ์›์น™์„ ์ ์šฉํ•˜์—ฌ ์„ค๊ณ„ํ•˜๋ฉด !

 

1. ์žฌ์‚ฌ์šฉ๊ณผ ์œ ์ง€๊ด€๋ฆฌ๊ฐ€ ์‰ฌ์šด, ๋ณ€๊ฒฝ์— ์œ ์—ฐํ•œ ์ฝ”๋“œ๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด๋Š” ํŠผํŠผํ•œ ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋ฉฐ ๋†’์€ ํ™•์žฅ์„ฑ์„ ๊ฐ€์ง€๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

2. ๋†’์€ ์‘์ง‘๋ ฅ๊ณผ ๋‚ฎ์€ ๊ฒฐํ•ฉ๋„ ( High Cohesion, Low coupling ) ์„
์ „๊ณต ์ฑ…์—์„œ ๋ณด๋Š”๊ฒŒ ์•„๋‹ˆ๊ณ  ๋‚ด ์ฝ”๋“œ์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋‹ค ! 

 

 

 

์ถ”๊ฐ€์ ์œผ๋กœ, Swift ์—์„œ๋„ SOLID ์›์น™์„ ์•Œ๊ณ  ์ ์šฉํ•ด์•ผ๋˜๋Š” ์ด์œ  ? 

 

Swift๋Š” ๋ฉ€ํ‹ฐํŒจ๋Ÿฌ๋‹ค์ž„ ์–ธ์–ด์ด์ง€๋งŒ Foundation , UIKit ๋“ฑ 

์ฝ”์ฝ”์•„ํ„ฐ์น˜ ํ”„๋ ˆ์ž„์›Œํฌ๋“ค์€ ๊ธฐ๋ณธ์ ์œผ๋กœ OOP์— ๊ทผ๊ฐ„์„ ๋‘๊ณ  ์žˆ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. 

SOLID ์›์น™์„ ์ œ๋Œ€๋กœ ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด ํ‰์†Œ์— ์“ฐ๊ณ  ์žˆ๋Š” ํด๋ž˜์Šค๋“ค์ด

์™œ ์ด๋Ÿฐ์‹์œผ๋กœ ๋งŒ๋“ค์–ด์กŒ๋Š”์ง€ ์•Œ์ˆ˜์žˆ๊ณ  ์•ž์œผ๋กœ ์šฐ๋ฆฌ๊ฐ€ ์ž‘์„ฑํ•  ์ฝ”๋“œ์—

์–ด๋–ป๊ฒŒ ๋…น์—ฌ๋‚ผ์ˆ˜ ์žˆ์„์ง€ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๊ฒ ์ฃ  ! 

 

์ฒ˜์Œ๋ถ€ํ„ฐ ์ฝ”๋“œ๋ฅผ ์ž˜ ์งค์ˆ˜๋Š” ์—†๊ฒ ์ง€๋งŒ,

์ตœ์†Œํ•œ ์ž˜๋ชป๋œ ์ฝ”๋“œ๊ฐ€ ์–ด๋–ค๊ฑด์ง€๋ฅผ ์•Œ๊ณ  ํ”ผํ•ด๊ฐ€์ž ^^_ ๋ผ๋Š” ์ปจ์…‰ 

 

๊ทธ๋Ÿฌ๋ฉด 5๊ฐ€์ง€ ์•ฝ์–ด์—๋Š” ์–ด๋–ค ๊ฒƒ๋“ค์ด ์žˆ๊ณ ,

Swift ์–ธ์–ด์—๋Š” ์–ด๋–ป๊ฒŒ ์ ์šฉ์ด ๋ ๊นŒ์š” ?

 

 

์•Œ์•„๋ณด๋Ÿฌ ๊ฐ€๋ด…์‹œ๋‹น.

 


1. SRP(Single Responsibility Principle) - ๋‹จ์ผ ์ฑ…์ž„ ์›์น™

 

ํด๋ž˜์Šค๋‚˜ ํ•จ์ˆ˜๋ฅผ ์„ค๊ณ„ํ•  ๋•Œ, ๊ฐ ๋‹จ์œ„๋“ค์€ ๋‹จ ํ•˜๋‚˜์˜ ์ฑ…์ž„๋งŒ์„ ๊ฐ€์ ธ์•ผํ•œ๋‹ค๋Š” ์›์น™ !

 

ํ•˜๋‚˜์˜ ํด๋ž˜์Šค๊ฐ€ ๋งŽ์€ ๋ฉ”์„œ๋“œ ๋ฐ ์—ญํ• ์„ ๊ฐ€์ง€๊ฒŒ ๋œ๋‹ค๋ฉด ? 

ํด๋ž˜์Šค ๋‚ด๋ถ€ ํ•จ์ˆ˜๋ผ๋ฆฌ ๊ฐ•ํ•œ ๊ฒฐํ•ฉ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

ํด๋ž˜์Šค ๋‚ด์—์„œ ์ˆ˜์ • ๋ฐ ์ถ”๊ฐ€๋ฅผ ์ง„ํ–‰ํ•  ๋•Œ,

๊ฐ€๋…์„ฑ ์ €ํ•˜ ๋ฐ ์œ ์ง€๋ณด์ˆ˜ ๋น„์šฉ ์ฆ๊ฐ€ ๋“ฑ์˜ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒ ์ฃ .. 

 

๊ฐ ํด๋ž˜์Šค ๋ณ„๋กœ ์ฑ…์ž„์„ ์ ์ ˆํ•˜๊ฒŒ ๋‚˜๋ˆ ์„œ

์‘์ง‘๋„๋Š” ๋†’๊ณ  ๊ฒฐํ•ฉ๋„๋Š” ๋‚ฎ์€ ํ”„๋กœ๊ทธ๋žจ์„ ์„ค๊ณ„ํ•˜๋Š”๊ฒŒ ๋‹จ์ผ ์ฑ…์ž„ ์›์น™ !

 

SRP์˜ ๊ฐ€์žฅ ๋Œ€ํ‘œ์ ์ธ ์œ„๋ฐ˜ ์‚ฌ๋ก€๋Š” Massive View Controller ํ˜„์ƒ์ž…๋‹ˆ๋‹ค.

์š”๊ฑฐ ๋งŽ์ด ๋“ค์–ด๋ดค์ฃ ..? ์ด๋Ÿฐ MVC์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด

MVVM, MVP, VIPER ๋“ฑ ์—ฌ๋Ÿฌ ๋‹ค๋ฅธ ํŒจํ„ด๋“ค์ด ์ƒ๊ฒจ๋‚˜๊ณ  ์‹œ๋„๋˜๊ณ  ์žˆ๋Š”๋ฐ,

๊ทธ๊ฒƒ๋“ค์˜ ๊ณตํ†ต์ ์€ ๋„ˆ๋ฌด ๋งŽ์€ ์—ญํ• ์„ ํ•˜๊ณ  ์žˆ๋Š” ๋ทฐ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ชผ๊ฐœ์„œ

๋‹จ์ผ ์ฑ…์ž„๋งŒ์„ ๊ฐ€์ง€๋Š” ์—ฌ๋Ÿฌ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๋ ค๊ณ  ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค ! 

 

SRP๋ฅผ ์ง€ํ‚ค๊ธฐ ์œ„ํ•ด ๋‹น์žฅ ์‹œ๋„ํ•ด๋ณผ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ ? 

ํด๋ž˜์Šค๋ฅผ ์ž‘๊ฒŒ ๋งŒ๋“ค์ž ! 

์‚ฌ์‹ค ํด๋ž˜์Šค๊ฐ€ ์ž‘๋‹ค๋Š” ๊ฒƒ์ด SRP์˜ ์ถฉ๋ถ„์กฐ๊ฑด์€ ์•„๋‹ˆ์ง€๋งŒ, ํ•„์š”์กฐ๊ฑด์ž…๋‹ˆ๋‹ค !

 

๊ฐ‘์ž๊ธฐ ์Šค์ณ์ง€๋‚˜๊ฐ€๋Š” ์•ฑ์žผ ํ”„๋กœ์ ํŠธ...

์Šค์œ„ํ”„ํŠธ ๋ฆฐํŠธ์— 10-200๋ฃฐ์„ ์ ์šฉํ•ด๋†จ๋˜... 

10-200๋ฃฐ์ด๋ž€ ํ•จ์ˆ˜๋Š” 10์ค„ ์ด๋‚ด, ํด๋ž˜์Šค๋Š” 200์ค„ ์ด๋‚ด๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.. 

 

์•ฑ์žผ ์ •๋„์˜ ํ”„๋กœ์ ํŠธ๋Š” ํฐ ๋ฌด๋ฆฌ์—†์ด ๊ฐ€๋Šฅํ–ˆ์ง€๋งŒ

๊ฐ€๋” ๊ธฐ๋Šฅ์ด ๋งŽ์•˜๋˜ ๋ทฐ์ปจ์€ .. ์ปค๋ฐ‹์ด ์•ˆ๋˜๊ฐ€์ง€๊ตฌ ๋™๋™ ๋ฆฌํŒฉํ† ๋ง ํ–ˆ์—ˆ๋Š”๋ฐ 

์ด๋Ÿฐ ํฐ ๊ทธ๋ฆผ์ด ์žˆ์—ˆ๋‹ค๋‹ˆ.. 

 

ํ•จ์ˆ˜๋Š” 10์ค„ ๋ฃฐ์„ ์ง€ํ‚ค๋ ค๋ฉด ํ•จ์ˆ˜๋Š” ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ ํ•ด์•ผ๋œ๋‹ค !!

๋ผ๋Š” ์›์น™์„ ์ง€ํ‚ฌ ์ˆ˜ ๋ฐ–์— ์—†๊ณ  ์ถ”์ƒํ™” ๋ ˆ๋ฒจ์— ๋Œ€ํ•ด ๊ณ ๋ฏผ์„ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ž‘์—…(ํ•จ์ˆ˜)์„ ์–ด๋Š ์ˆ˜์ค€๊นŒ์ง€ ์ชผ๊ฐœ์„œ

์„ค๋ช…(์ถ”์ƒํ™”)ํ•  ๊ฒƒ์ธ์ง€์— ๋Œ€ํ•ด ๊ณ ๋ฏผ์„ ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค.

 

โ€˜ํด๋ž˜์Šค๋Š” 200์ค„โ€™ ๋ฃฐ์„ ์ง€ํ‚ค๋ ค๋ฉด ํ”„๋กœํผํ‹ฐ๋‚˜ ํ•จ์ˆ˜, ๋ฉ”์„œ๋“œ๋ฅผ

๊ทธ๋ƒฅ ์†์ด ๊ฐ€๋Š” ๊ณณ ์•„๋ฌด๋ฐ๋‚˜ ๋งŒ๋“ค์–ด์„œ ์“ธ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๊ผญ ์–˜๊ฐ€ ์ด ๊ณณ์— ์žˆ์–ด์•ผ ํ•˜๋Š” ์ด์œ ๋ฅผ ์ฐพ์•„์•ผ ํ•˜๊ณ ,

ํ•ด๋‹น ํด๋ž˜์Šค์— ์žˆ์„ ์ด์œ ๊ฐ€ ์—†์œผ๋ฉด SRP ์œ„๋ฐ˜์ด๋‹ค.

 

๊ฐ€์žฅ ์‰ฝ๊ฒŒ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ• ํ•˜๋‚˜๋Š”, ํ•จ์ˆ˜๋‚˜ ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์—์„œ

self์˜ ํ”„๋กœํผํ‹ฐ๋‚˜ ๋ฉ”์„œ๋“œ๋ฅผ ์–ผ๋งˆ๋‚˜ ์“ฐ๊ณ  ์žˆ๋Š”์ง€ ๋ณด๋Š” ๊ฒƒ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

 

๋งŒ์•ฝ ํ•˜๋‚˜๋„ ์“ฐ๊ณ  ์žˆ์ง€ ์•Š๋‹ค๋ฉด ๊ทธ ํด๋ž˜์Šค ์•ˆ์— ์žˆ์„ ์ด์œ ๊ฐ€ ์ „ํ˜€ ์—†๋Š” ๊ฒƒ์ด๋ผ๊ณ  

์ƒ๊ฐํ•ด๋„ ๋˜๊ฒ ์ฃ ..? ์•„๋ฌด๋ž˜๋„..? 

 

๋˜๋Š” self์˜ ํ˜ธ์ถœ ๋นˆ๋„๊ฐ€ ์ ์„์ˆ˜๋ก ํด๋ž˜์Šค์™€ ์—ฐ๊ด€์„ฑ์ด ๋–จ์–ด์ง€๋Š” ๊ฒƒ์ด๋‹ˆ

๋‚˜์ค‘์— ํด๋ž˜์Šค๋ฅผ ๋ฆฌํŒฉํ† ๋ง ํ•˜๊ฑฐ๋‚˜ ๋‹ค์ด์–ดํŠธ ์‹œ์ผœ์•ผ ํ•  ์ƒํ™ฉ์ด ์˜ค๋ฉด ์šฐ์„ ์ ์œผ๋กœ ๋‚ด์ซ“์„ ํ›„๋ณด๋กœ 

์ ์ฐ์–ด๋‘๋Š” ๊ทธ๋Ÿฐ... ๊ฒƒ์ด์ฃ  ! 

 

SRP๋Š” ๋ชจ๋“  ํŒจํ„ด์˜ ์‹œ์ž‘์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. 

SRP๋ฅผ ์ œ๋Œ€๋กœ ์ง€ํ‚ค์ง€ ๋ชปํ•œ ์ฑ„๋กœ ์ฝ”๋”ฉ์„ ํ•˜๋ฉด

๊ทธ ์–ด๋–ค ํŒจํ„ด์„ ๋„์ž…ํ•ด๋ณด๋ ค๊ณ  ํ•ด๋„ ์ž˜ ์•ˆ๋  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์–ด๋ฉ”๋ฉ” SRP๋ผ๋„.. ์ผ๋‹จ.. ์•„์ขŒ์ขŒ

 

ํด๋ž˜์Šค๋Š” ํ•˜๋‚˜์˜ ์—ญํ• ๋งŒ ํ•ด์•ผํ•œ๋‹ค๋Š” ๊ฒƒ,

๊ฐ์ฒด์ง€ํ–ฅ์„ ๋ฐฐ์šฐ๋ฉด์„œ ๊ฐ€์žฅ ๋จผ์ € ๋ฐฐ์šฐ๋Š” ์›์น™์ž„์—๋„ ์ •๋ง ์ง€ํ‚ค๊ธฐ ์‰ฝ์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™๋„ค์š” !

 

 

์˜ˆ์‹œ ์ฝ”๋“œ 

 

๋‚˜์œ ์˜ˆ์‹œ 

class LoginService {
    func login(id: String, pw: String) {
        let userData = requestLogin()
        let user = decodeUserInform(data: userData)
        saveUserOnDatabase(user: user)
    }
    
    private func requestLogin() -> Data {
        // Call API
        return Data()
    }
    
    private func decodeUserInform(data: Data) -> User {
        // Decoding User Inform from Data
        return User(name: "", age: 10)
    }
    
    private func saveUserOnDatabase(user: User) {
        // Save User
    }
}

์œ„์˜ LoginService๋ผ๋Š” ํด๋ž˜์Šค ๋‚ด๋ถ€์—์„œ 

API ํ˜ธ์ถœ, ๋””์ฝ”๋”ฉ, ์œ ์ € ๋ฐ์ดํ„ฐ ์ €์žฅ ๋“ฑ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์—ญํ• ์„ ํ•˜๊ณ  ์žˆ๋„ค์š” ! 

์ฆ‰, ํด๋ž˜์Šค ๋‚ด๋ถ€์—์„œ ํ•˜๋‚˜์˜ ์ฑ…์ž„์ด ์•„๋‹Œ ์—ฌ๋Ÿฌ์ฑ…์ž„์„ ๋™์‹œ์— ์ง€๊ณ  ์žˆ๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค 

 

์ข‹์€ ์˜ˆ์‹œ

protocol APIHandlerProtocol {
    func requestLogin() -> Data
}

protocol DecodingHandlerProtocol {
    func decode<T>(from data: Data) -> T
}

protocol DBhandlerProtocol {
    func saveOnDatabase<T>(inform: T)
}

class LoginService {
    let apiHandler: APIHandlerProtocol
    let decodingHandler: DecodingHandlerProtocol
    let dbHandler: DBhandlerProtocol
    
    init(apiHandler: APIHandlerProtocol,
         decodingHandler: DecodingHandlerProtocol,
         dbHandler: DBhandlerProtocol) {
        self.apiHandler = apiHandler
        self.decodingHandler = decodingHandler
        self.dbHandler = dbHandler
    }
    
    func login() {
        let loginData = apiHandler.requestLogin()
        let user: User = decodingHandler.decode(from: loginData)
        dbHandler.saveOnDatabase(inform: user)
    }
}

์œ„์˜ ๋‚˜์œ ์—์‹œ์™€ ๋น„๊ตํ•ด์„œ ๊ฐ๊ฐ DB, Decoder, APIHandler ์—ญํ• ์„ ํ•˜๋Š”

ํ”„๋กœํ† ์ฝœ์„ ๋งŒ๋“ค์–ด์ฃผ๊ณ  ๊ฐ์ž์˜ ์—ญํ• ๋งŒํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋งŒ์„ ๊ตฌํ˜„ํ•˜๊ฒŒ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  LoginService์—์„œ๋Š” ๋‹จ์ง€ ์ด ํ”„๋กœํ† ์ฝœ๋“ค์„ ํ™œ์šฉํ•ด์„œ ์ƒํ˜ธ์ž‘์šฉ๋งŒ์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ด์ „๊ณผ ๋น„๊ตํ•ด์„œ ํ™•์‹คํžˆ LoginService๋Š” ๋กœ๊ทธ์ธ์— ๊ด€๋ จ๋œ ๋กœ์ง๋งŒ์„ ๋‹ค๋ฃจ๋Š”๋ฐ

๊ฐ๊ฐ์˜ ๋ชจ๋“ˆ๋“ค์„ ํ™œ์šฉํ•ด์„œ ๋กœ๊ทธ์ธ์— ๊ด€ํ•œ ์ฑ…์ž„๋งŒ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 


 

 

2. OCP(Open-Closed Principle) - ๊ฐœ๋ฐฉ, ํ์‡„ ์›์น™

 

ํ™•์žฅ์—๋Š” ์—ด๋ ค์žˆ์œผ๋‚˜ ๋ณ€๊ฒฝ์—๋Š” ๋‹ซํ˜€์žˆ์–ด์•ผํ•œ๋‹ค๋Š” ์›์น™ 

 

ํ™•์žฅ์— ์—ด๋ ค์žˆ๋‹ค ? ํด๋ž˜์Šค์˜ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•˜๋Š” ๊ฒƒ์ด ์‰ฌ์›Œ์•ผ๋œ๋‹ค.

๋ณ€๊ฒฝ์—๋Š” ๋‹ซํ˜€์žˆ๋‹ค ? ๊ธฐ์กด์— ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š” ๊ฒƒ๋“ค์„ ๋ฐ”๊พธ์ง€ ์•Š๊ณ  ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์–ด์•ผํ•œ๋‹ค.

 

์ฆ‰, ์–ด๋–ค ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ๋•Œ ๊ธฐ์กด์˜ ์ฝ”๋“œ๋Š” ๋งŒ์ง€์ง€ ์•Š๊ณ  ์ƒˆ๋กœ ๋™์ž‘ํ•˜๋Š” ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด์„œ๋งŒ

์ฝ”๋“œ๊ฐ€ ์ž‘์„ฑ์ด ๋˜์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

์š”๊ตฌ์‚ฌํ•ญ์˜ ๋ณ€๊ฒฝ์ด๋‚˜ ์ถ”๊ฐ€์‚ฌํ•ญ์ด ์ƒ๊ธฐ๋”๋ผ๋„ ๊ธฐ์กด ๊ตฌ์„ฑ์š”์†Œ๋Š” ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ ,

ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋งŒ ํ™•์žฅ์„ ํ†ตํ•ด์„œ ์žฌ์‚ฌ์šฉ ํ• ์ˆ˜ ์žˆ๊ฒŒ !! 

 

์ด๋Ÿฌํ•œ ํŠน์„ฑ๋“ค์€ ์ถ”์ƒํ™”๋ฅผ ํ†ตํ•ด์„œ ์ด๋ฃจ์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค !

์Šค์œ„ํ”„ํŠธ์—์„œ ์ถ”์ƒํ™”๋Š” ์ฃผ๋กœ Protocol์„ ํ†ตํ•ด ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค !!

 

 ์œ„์˜ SRP ์˜ˆ์ œ์ฒ˜๋Ÿผ ํ”„๋กœํ† ์ฝœ์„ ์ด์šฉํ•ด์„œ

๊ตฌํ˜„ํ•œ๋‹ค๋ฉด ๋กœ์ง์—์„œ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์žˆ์„ ๋•Œ ๊ฐ๊ฐ์˜ ํ”„๋กœํ† ์ฝœ์„ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ์™ธ๋ถ€์—์„œ ์ฃผ์ž…ํ•˜๋ฉด

๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์—๋„ ๋ณ€ํ™”์—†์ด ๋Œ€์‘์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.!

 

OCP๋ฅผ ์ž˜ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ณ€ํ•˜์ง€ ์•Š์„ ๋ณธ์งˆ์ ์ธ ํŠน์ง• (์ธํ„ฐํŽ˜์ด์Šค) ์™€ 

๋‹ค๋ฅธ ์š”์†Œ๋กœ๋ถ€ํ„ฐ ์‹๋ณ„๋  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด์˜ ๋ณธ์งˆ์ ์ธ ํŠน์ง• (์ถ”์ƒํ™”)๋ฅผ ์ž˜ ๊ตฌ๋ถ„ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š” !

 

OCP ์œ„๋ฐ˜์˜ ๋Œ€ํ‘œ์ ์ธ ์˜ˆ๋Š” ์–ด๋–ค ํƒ€์ž…์— ๋Œ€ํ•œ ๋ฐ˜๋ณต์ ์ธ ๋ถ„๊ธฐ๋ฌธ์ด๋‹ค. 

์ฆ‰, ํ•˜๋‚˜์˜ enum์— ๋Œ€ํ•ด ์—ฌ๋Ÿฌ ๊ตฐ๋ฐ์—์„œ ๋ฐ˜๋ณต์ ์œผ๋กœ if/switch ๋ฌธ์„ ์“ฐ๊ณ  ์žˆ๋‹ค๋ฉด

๊ณ ๋ฏผ์„ ํ•ด๋ด์•ผํ•œ๋‹ค. ์™œ๋ƒํ•˜๋ฉด, ์ด๋Ÿฐ๊ฒฝ์šฐ์— ๊ธฐ๋Šฅ ์ถ”๊ฐ€๋Š” case๋ฅผ ํ•œ์ค„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋˜๋‹ˆ๊นŒ ์‰ฝ์ง€๋งŒ

๊ทธ๋ ‡๊ฒŒ ํ•˜๋Š” ์ˆœ๊ฐ„ ํ•ด๋‹น enum์„ ์Šค์œ„์นญ ํ•˜๊ณ  ์žˆ๋Š” ๋ชจ๋“  ์ฝ”๋“œ๋ฅผ ์ฐพ์•„์„œ ์ˆ˜์ •ํ•ด์ค˜์•ผํ•œ๋‹ค.

 

OCP๋Š” if/switch๋ฅผ ์ตœ๋Œ€ํ•œ ์•ˆ ์“ฐ๋Š” ๋ฐฉ๋ฒ•์„ ํ†ตํ•ด ์—ฐ์Šตํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ชจ๋“  ๋ถ„๊ธฐ๋ฌธ์„ ์—†์• ๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ณ .. enum๊ฐ™์ด ํƒ€์ž…์„ ๋ถ„๊ธฐํ•˜๋Š” ์ง€์ ์— ๋Œ€ํ•ด์„œ !

 

๊ทผ๋ฐ ์ด ์–˜๊ธฐ๋ฅผ ๋“ฃ๊ณ  ๋ง๋„ ์•ˆ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š”๊ฒŒ ๋‹น์—ฐํ•˜๋‹ค.. 

์–ด๋–ป๊ฒŒ if/switch ์—†์ด ๋ถ„๊ธฐ๋ฅผ ํ•˜๋ƒ๊ณ  .. 

 

์•ž์„œ ์–ธ๊ธ‰ํ•œ 10-200๋ฃฐ๊ณผ๋„ ์ƒํ˜ธ๋ณด์™„์ ์ด๋ผ๋Š”๋ฐ ๋ถ„๊ธฐ๋ฌธ์„ ์—†์• ๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋„ 

ํ•จ์ˆ˜ ๋ฐ ํด๋ž˜์Šค์˜ ๊ธธ์ด๋ฅผ ๋งŽ์ด ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

 

if/switch ๋ฌธ์„ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ• 2๊ฐ€์ง€ 

1. protocol์„ ๋งŒ๋“ค๊ณ  ์ƒ์†๋ฐ›์•„ ์“ฐ๋Š” ๋ฐฉ๋ฒ• - ์ง์ ‘์ ์œผ๋กœ OCP๋ฅผ ์ง€ํ‚ค๋Š” ๊ตฌ์กฐ

2. ๊ฐ„๋‹จํ•˜๊ฒŒ ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ• - OCP๋ฅผ ์ง€ํ‚ค๋Š” ๊ตฌ์กฐ๋Š” ์•„๋‹ˆ์ง€๋งŒ, ๋ถ„๊ธฐ๋ฌธ์„ ์—†์• ๊ณ  ์‹ถ์„๋–„ 

์ œํ•œ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹๋‹ค. 

 

์˜ˆ์‹œ์ฝ”๋“œ 

1๋ฒˆ ํ”„๋กœํ† ์ฝœ ํ™œ์šฉ !

 

์ฒซ๋ฒˆ์งธ ์˜ˆ์‹œ - ๋™๋ฌผ

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

class Dog {
    func makeSound() {
        print("๋ฉ๋ฉ")
    }
}

class Cat {
    func makeSound() {
        print("์•ผ์˜น")
    }
}

class Zoo {
    var dogs: [Dog] = [Dog(), Dog(), Dog()]
    var cats: [Cat] = [Cat(), Cat(), Cat()]
    
    func makeAllSounds() {
        dogs.forEach {
            $0.makeSound()
        }
        
        cats.forEach {
            $0.makeSound()
        }
    }
}

์ด๋ ‡๊ฒŒ ๋œ๋‹ค๋ฉด ์ƒˆ๋กœ์šด ๋™๋ฌผ์ด ์ƒ๊ฒผ์„ ๋•Œ Class๋กœ ์ƒˆ๋กญ๊ฒŒ ์ •์˜ํ•˜๊ณ  

Zoo์— ๋˜ ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ๋™๋ฌผ์— ๋งž๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์ค˜์•ผ๊ฒ ์ฃ .. ! 

์ด๋ ‡๊ฒŒ ๋ถˆํ•„์š”ํ•œ ๋ฉ”์„œ๋“œ๋“ค์ด ๋Š˜์–ด๋‚˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

๋˜, ์—ฌ๊ธฐ์„œ dog ํด๋ž˜์Šค์˜ makeSound() ๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ฒŒ ๋˜๋ฉด,

์ด์ œ๋Š” dog ํด๋ž˜์Šค์— ์—†๋Š” ๋ฉ”์„œ๋“œ์ด๊ธฐ ๋•Œ๋ฌธ์— Zoo class์—์„œ

dogs.makeSound() ๋ถ€๋ถ„์€ ์—๋Ÿฌ๊ฐ€ ๋‚˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

๋ฌธ์ œ : ํด๋ž˜์Šค๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด ๋ฉ”์„œ๋“œ๋ฅผ ๊ณ„์† ์ˆ˜์ •ํ•ด์•ผ๋˜๊ณ , ๋น„์Šทํ•œ ํ˜•ํƒœ์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ๊ณ„์† ์ถ”๊ฐ€๋˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ํด๋ž˜์Šค์˜ ๋ณธ์งˆ์ ์ธ ํŠน์ง• + ํ™•์žฅ๋˜๋Š” ๋ถ€๋ถ„์„ ์–ด๋–ป๊ฒŒ ๊ตฌ๋ถ„ํ•˜๋Š”๊ฒŒ ์ข‹์„๊นŒ์š”?

 

protocol Animal {
    func makeSound()
}

class Dog: Animal {
    func makeSound() {
        print("๋ฉ๋ฉ")
    }
}

class Cat: Animal {
    func makeSound() {
        print("์•ผ์˜น")
    }
}

class Zoo {
    var animals: [Animal] = []
    
    func makeAllSounds() {
        animals.forEach {
            $0.makeSound()
        }
    }
}

์Šค์œ„ํ”„ํŠธ์—์„œ๋Š” ๋ณ€ํ•˜์ง€ ์•Š๋Š” ๋ถ€๋ถ„์„ ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜์—ฌ 

์ธํ„ฐํŽ˜์ด์Šคํ™” ํ•ฉ๋‹ˆ๋‹ค. ๋ณ€ํ•˜๋Š” ๋ถ€๋ถ„์€ ๊ฐ ํด๋ž˜์Šค๋ณ„๋กœ ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•ด ๊ตฌํ˜„ํ•ด์ฃผ๋ฉด ๋˜๊ฒ ์ฃ .

 

์ด๋ ‡๊ฒŒ ํ”„๋กœํ† ์ฝœ์„ ํ™œ์šฉํ•ด์„œ ์„ค๊ณ„๋ฅผ ์ง„ํ–‰ํ•˜๊ฒŒ ๋˜๋ฉด ์ƒˆ๋กญ๊ฒŒ ๋™๋ฌผ์ด ์ถ”๊ฐ€๋˜์–ด๋„

๊ธฐ์กด์˜ ์ฝ”๋“œ๋Š” ๋งŒ์ง€์ง€ ์•Š๊ณ  ๊ทธ์ € class ์ƒˆ๋กœ์šด๋™๋ฌผ: Animal์œผ๋กœ ์„ ์–ธํ•˜์—ฌ

๊ตฌํ˜„๋งŒํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ๋˜๋ฉด Zoo ํด๋ž˜์Šค์—์„œ๋Š” ๊ธฐ์กด์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ˆ˜์ •ํ•  ํ•„์š” ์—†์ด

์ƒˆ๋กœ์šด ๋™๋ฌผ๋“ค์„ ์ถ”๊ฐ€ํ•˜์—ฌ ํ•จ์ˆ˜๋ฅผ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

๊ฒฐ๋ก ์ ์œผ๋กœ ํ”„๋กœํ† ์ฝœ์€ ๋ณ€๊ฒฝ์— ๋‹ซํ˜€์žˆ๊ธฐ ๋•Œ๋ฌธ์— makeSound() ๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ˆ˜์ •ํ•  ํ•„์š”๊ฐ€ ์—†๊ณ 

์ƒˆ๋กœ์šด ๋™๋ฌผ์ด ์ถ”๊ฐ€๋˜๋Š” ์ƒํ™ฉ์—์„œ๋Š” ํ™•์žฅ์— ์—ด๋ ค์žˆ๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ! 

 

 

2๋ฒˆ ๋”•์…”๋„ˆ๋ฆฌ ํ™œ์šฉ ! 

์•ž์„œ ์„ค๋ช…์—์„œ ๋ถ„๊ธฐ๋ฌธ์„ ์—†์• ๊ณ  ์‹ถ์„๋•Œ๊ฐ€ ์žˆ๋‹ค๋ฉด , ์š”๋ ‡๊ฒŒ ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด๋ณด๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋„ค์š” ! 

switch reason {
  case .initializing:
    self.instructionMessage = "Move your phone".localized
  case .excessiveMotion:
    self.instructionMessage = "Slow down".localized
  case .insufficientFeatures:
    self.instructionMessage = "Keep moving your phone".localized
  case .relocalizing:
    self.instructionMessage = "Move your phone".localized
}

//์ ์ ˆํ•œ ๊ณณ์— ๋”•์…”๋„ˆ๋ฆฌ ์ƒ์„ฑ
let trackingStateMessages: [TrackingState.Reason : String] 
                         = [.initializing.        : "Move your phone".localized,
                            .excessiveMotion      : "Slow down".localized,
                            .insufficientFeatures : "Keep moving your phone".localized,
                            .relocalizing         : "Move your phone".localized]

//switch๋ฌธ ๋Œ€์ฒด
self.instructionMessage = trackingStateMessages[reason]

 

3๋ฒˆ ์ถ”๊ฐ€ ์˜ˆ์‹œ 

 

1๋ฒˆ ์˜ˆ์‹œ์— OCP๋ฅผ ์ ์šฉํ•ด๋ณด๋ฉด, ์ด๋ ‡๊ฒŒ ๋ณ€ํ•˜์ง€ ์•Š๋Š” ๋ถ€๋ถ„์€ ํ”„๋กœํ† ์ฝœ๋กœ ์„ ์–ธํ•ด์ฃผ๊ณ ,

๊ฐ ์ข…๋ฅ˜๋ณ„ ํ•ธ๋“ค๋Ÿฌ์—์„œ ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•˜์—ฌ ๊ตฌํ˜„ํ•ด์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ 

LoginService์—์„œ ํ•„์š”ํ•œ ํƒ€์ž…์˜ apihandler๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ! 

protocol APIHandlerProtocol {
    func requestAPI()
}

class getHandler: APIHandlerProtocol {
    func requestAPI() {
        print("getHandler")
    }
}

class postHandler: APIHandlerProtocol {
    func requestAPI() {
        print("postHandler")
    }
}

class putHandler: APIHandlerProtocol {
    func requestAPI() {
        print("putHandler")
    }
}

class APIService {
    var apiHandler: APIHandlerProtocol

    init(handlerType: APIHandlerProtocol) {
        apiHandler = handlerType
    }
    
    func requestAPIByHandler() {
        apiHandler.requestAPI()
    }
}

import UIKit

class ViewController: UIViewController {


    override func viewDidLoad() {
        super.viewDidLoad()
        let someService = APIService(handlerType: getHandler())
        someService.requestAPIByHandler()
        
        someService.apiHandler = putHandler()
        someService.requestAPIByHandler()
    }
}

 

 


 

 

3. LSP(Liskov Substitution Principle) - ๋ฆฌ์Šค์ฝ”ํ”„ ์น˜ํ™˜ ์›์น™

 

๋ถ€๋ชจํด๋ž˜์Šค๋กœ ๋™์ž‘ํ•˜๋Š” ๊ณณ์—์„œ ์ž์‹ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ๋„ฃ์–ด์ฃผ์–ด๋„ ๋Œ€์ฒด๊ฐ€ ๊ฐ€๋Šฅํ•ด์•ผํ•œ๋‹ค๋Š” ์›์น™

์ž์‹ ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„ํ• ๋–„, ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๊ธฐ๋Šฅ์ด๋‚˜ ๋Šฅ๋ ฅ๋“ค์„ ๋ฌผ๋ ค๋ฐ›์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์ž์‹ ํด๋ž˜์Šค๋Š” ๋™์ž‘์„ ํ• ๋•Œ ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๊ธฐ๋Šฅ๋“ค์„ ์ œํ•œํ•˜๋ฉด ์•ˆ๋œ๋‹ค๋Š” ๋œป ! 

 

์ฆ‰, ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ํƒ€์ž…์— ์ž์‹ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋„ฃ์–ด๋„ ๋˜‘๊ฐ™์ด ๋™์ž‘ํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

์ž์‹ํด๋ž˜์Šค๊ฐ€ ๋ถ€๋ชจํด๋ž˜์Šค์˜ ๊ธฐ๋Šฅ์„ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•ด์„œ ๊ธฐ๋Šฅ์„ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ์ œํ•œํ•˜๋Š” ๊ฒฝ์šฐ์— 

๊ฒฐ๊ณผ๊ฐ’์ด ๋‹ค๋ฅด๊ฒŒ ๋‚˜์˜ค๋ฏ€๋กœ, LSP ์›์น™์„ ์œ„๋ฐ˜ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. 

 

 

์ „ํ˜•์ ์ธ ์œ„๋ฐ˜ ์‚ฌ๋ก€๋กœ๋Š” ์ง์‚ฌ๊ฐํ˜•์„ ์ƒ์†๋ฐ›์•„์„œ ๋งŒ๋“  ์ •์‚ฌ๊ฐํ˜• ํด๋ž˜์Šค๋ฅผ ์ƒ๊ฐํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค! 

์ •์‚ฌ๊ฐํ˜•์€ ๋„ˆ๋น„์™€ ๋†’์ด๊ฐ€ ๊ฐ™์•„์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋„ˆ๋น„์™€ ๋†’์ด๋ฅผ ์ž์œ ๋กญ๊ฒŒ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋Š”

์ง์‚ฌ๊ฐํ˜• ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๋™์ž‘์„ ์ œํ•œํ•ด์•ผ๋งŒ ์›ํ•˜๋Š” ๋™์ž‘์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ๊ฐ€ LSP์˜ ์œ„๋ฐ˜์ด๋‹ค.

LSP๋ฅผ ์ง€ํ‚ค๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ง์‚ฌ๊ฐํ˜•์ด ์ •์‚ฌ๊ฐํ˜•์„ ์ƒ์†๋ฐ›๊ฑฐ๋‚˜, ์•„๋‹ˆ๋ฉด ๋„ˆ๋น„์™€ ๋†’์ด๋ฅผ ์•„์˜ˆ let์œผ๋กœ ๋งŒ๋“ค์–ด๋ฒ„๋ฆฝ์‹œ๋‹ค !! 

 

๋‚˜์œ ์˜ˆ์‹œ

class Rectangle {
    var width: Float = 0
    var height: Float = 0
    
    var area: Float {
        return width * height
    }
}

class Square: Rectangle {
    override var width: Float {
        didSet {
            height = width
        }
    }
}

func printArea(of rectangle: Rectangle) {
	rectangle.height = 3
	rectangle.width = 6
	print(rectangle.area)
}

let rectangle = Rectangle()
printArea(of: rectangle)
// 18

let square = Square()
printArea(of: square)
// 36

์‹ค์ œ๋กœ ์ •์‚ฌ๊ฐํ˜•์€ ์ง์‚ฌ๊ฐํ˜•์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ์›๋ฆฌ์— ๋”ฐ๋ผ ํ”„๋กœ๊ทธ๋žจ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค๊ณ„ํ•˜๊ฒŒ ๋˜๋ฉด ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

didset ๋ถ€๋ถ„์—์„œ ๋ถ€๋ชจ์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉ์„ ํ†ตํ•ด 

๋ณ€๊ฒฝํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ž์‹ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์„œ 

๋˜‘๊ฐ™์€ ๋ฉ”์„œ๋“œ์— ๋„ฃ์–ด๋„ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ’์ด ๋‚˜์˜ค๊ฒŒ ๋ฉ๋‹ˆ๋‹ค !

 

์ด ๊ฒฝ์šฐ ๋ถ€๋ชจ์˜ ์—ญํ• ์„ ์ž์‹ ์ธ์Šคํ„ด์Šค์—์„œ ๋™์ผํ•˜๊ฒŒ ์ˆ˜ํ–‰ํ•˜๊ณ  ์žˆ์ง€

๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์— LSP ์›์น™์„ ์œ„๋ฐ˜ํ•œ ์‚ฌ๋ก€๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šด๋‹ค !

 

์ข‹์€ ์˜ˆ์‹œ 

protocol Shape {
    var area: Float { get }
}

class Rectangle: Shape {
    let width: Float
    let height: Float
    
    var area: Float {
        return width * height
    }
    
    init(width: Float,
         height: Float) {
        self.width = width
        self.height = height
    }
}

class Square: Shape {
    let length: Float
    
    var area: Float {
        return length * length
    }
    
    init(length: Float) {
        self.length = length
    }
}

์œ„์™€ ๊ฐ™์ด Rectangle, Square ๋‘˜๋‹ค Shape๋ผ๋Š” ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ ํ›„, 

์‹ค์ œ ๊ตฌํ˜„๋ถ€(area)๋ฅผ ํด๋ž˜์Šค์—๊ฒŒ ๋„˜๊ธฐ๋Š” ํ˜•ํƒœ๋กœ ์„ค๊ณ„ํ•˜๋ฉด LSP์— ์–ด๊ธ‹๋‚˜์ง€ ์•Š๊ณ  ํ”„๋กœ๊ทธ๋žจ์„ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ๊ฒ ์ฃ  !

Shape์˜ ์ž๋ฆฌ๋ฅผ Square, Rectangle ๋‘˜ ๋‹ค ๋ชจ๋‘ ๋Œ€์ฒด๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— 

LSP๋ฅผ ์œ„๋ฐ˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. !

 

ํ•˜์ง€๋งŒ, LSP๋ฅผ ์ ˆ๋Œ€ ์–ด๊ธฐ์ง€ ์•Š๊ณ  ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•˜๋Š”๊ฑด ์–ด๋ ค์šด ์ผ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค..

ํ•˜์ง€๋งŒ ๋„ˆ๋ฌด ๋งŽ์€ ๊ณณ์—์„œ LSP๋ฅผ ์–ด๊ธด๋‹ค๋ฉด ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธด๋‹ค.

 

๋‹ค๋ฅธ ํ‹ฐ์Šคํ† ๋ฆฌ ์ฐธ๊ณ ... 

 

์ƒ์œ„ ํด๋ž˜์Šค๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ฝ”๋”ฉํ•  ์ˆ˜ ์—†์–ด์ง€๊ณ , ๊ทธ๋ ‡๊ฒŒ๋˜๋ฉด ์ƒ์† ์ž์ฒด๊ฐ€ ์˜๋ฏธ๊ฐ€ ์—†์–ด์ง€๊ณ  OCP์กฐ์ฐจ ์ง€ํ‚ฌ์ˆ˜ ์—†๊ฒŒ ๋œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด UITableView๋Š” UITableViewCell์„ ๊ธฐ์ค€์œผ๋กœ ๋งŒ๋“ค์–ด์ ธ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—

์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ์ปค์Šคํ…€ ์…€์ด LSP๋ฅผ ์ง€ํ‚ค์ง€ ์•Š๋Š”๋‹ค๋ฉด ํ…Œ์ด๋ธ”๋ทฐ๋„ ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค.

๋˜ํ•œ protocol๋ฅผ ๋งŒ๋“œ๋Š” ์ด์œ ๋„ ์ถ”์ƒํ™”๋œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•ด์„œ์ธ๋ฐ

์ƒ์†๋ฐ›์€ ํƒ€์ž…์ด protocol์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ‡ดํ™”์‹œ์ผœ๋ฒ„๋ฆฌ๋ฉด

ํ”„๋กœํ† ์ฝœ์„ ๊ธฐ์ค€์œผ๋กœ ์ž‘์„ฑ๋œ ์ฝ”๋“œ๋“ค์ด ์ค„์ค„์ด ๋ง๊ฐ€์งˆ ์ˆ˜ ๋ฐ–์— ์—†๋‹ค.

 

์ƒ์†์€ ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ด๊ณ  ์ž˜ ์“ฐ๋ฉด ์œ ์šฉํ•˜์ง€๋งŒ ์ž˜๋ชป๋œ ์ƒ์†์„ ๋งŒ๋“ค๋ฉด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฐ˜๋ฉด ๋•Œ์— ๋”ฐ๋ผ์„œ๋Š” LSP๋ฅผ ์œ„๋ฐ˜ํ•จ์œผ๋กœ์จ ํŽธ๋ฆฌํ•จ๊ณผ ๋‹จ์ˆœํ•จ์„ ์–ป๊ฒŒ ๋  ์ˆ˜๋„ ์žˆ๋‹ค.

 

๊ฒฐ๋ก ์ ์œผ๋กœ, LSP๋ฅผ ๋ชจ๋“  ๊ณณ์—์„œ ์ง€ํ‚ค๋ ค๊ณ ๋งŒ ํ•˜๋ฉด ๋น„ํšจ์œจ์ ์ด๊ณ 

๋„ˆ๋ฌด ์ž์ฃผ ์œ„๋ฐ˜ํ•˜๋ฉด ์˜ˆ์ƒํ•˜์ง€ ๋ชปํ•œ ๊ฒฐ๊ณผ๋“ค ๋•Œ๋ฌธ์— ์•ˆ์ •์„ฑ์„ ํ•ด์น˜๊ฒŒ ๋œ๋‹ค.

๊ทธ๋Ÿฌ๋ฏ€๋กœ ์ƒ์†์„ ๋งŒ๋“ค๋•Œ๋Š” LSP ์œ„๋ฐ˜์ธ์ง€ ์•„๋‹Œ์ง€๋ฅผ ์ˆ™์ง€ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๊ฒ ๋‹ค.

 

๊ฒฐ๋ก  : ์ง€๋‚˜์นœ LSP ๋Š” ๋น„ํšจ์œจ์ ์ด๊ณ , ์ง€๋‚˜์นœ LSP ์œ„๋ฐ˜์€ ์•ˆ์ •์„ฑ์„ ํ•ด์น˜๊ธฐ ๋•Œ๋ฌธ์—

๋‘˜ ์‚ฌ์ด์—์„œ ์–ด๋Š์ •๋„ ์ถ”๊ตฌํ•  ๊ฒƒ์ธ์ง€์— ๋Œ€ํ•œ ํŒ๋‹จ์ด ์ค‘์š”ํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค ! 

 

 


 

 

 

 

4. ISP(Interface Segregation Principle) - ์ธํ„ฐํŽ˜์ด์Šค ๋ถ„๋ฆฌ ์›์น™

 

์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ผ๋ฐ˜ํ™”ํ•˜์—ฌ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ฑ„ํƒํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค

๊ตฌ์ฒด์ ์ธ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ฑ„ํƒํ•˜๋Š” ๊ฒƒ์ด ๋” ์ข‹๋‹ค๋Š” ์›์น™

 

์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์„ค๊ณ„ํ•  ๋•Œ, ๊ตณ์ด ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์ฑ„ํƒํ•˜์—ฌ ๊ตฌํ˜„ํ•˜์ง€ ๋ง๊ณ 

์˜คํžˆ๋ ค ํ•œ ๊ฐ€์ง€์˜ ๊ธฐ๋Šฅ๋งŒ์„ ๊ฐ€์ง€๋”๋ผ๋„ ์ •๋ง ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ๋งŒ์„ ๊ฐ€์ง€๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋ถ„๋ฆฌํ•˜๋ผ๋Š” ๊ฒƒ ! 

 

๋ญ”์†Œ๋ฆฌ๋ƒ.. 

์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๊ตฌํ˜„ํ•˜์ง€๋งˆ๋ผ !

์Šค์œ„ํ”„ํŠธ์—์„œ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ”„๋กœํ† ์ฝœ์„ ํ™œ์šฉํ•˜์—ฌ ์ฒ˜๋ฆฌํ•˜์ฃ  ! 

 

ํ”„๋กœํ† ์ฝœ์„ ์„ค๊ณ„ํ•˜๋‹ค๋ณด๋ฉด, ๋‹ค์–‘ํ•œ ๋ฉ”์„œ๋“œ๊ฐ€ ๋“ค์–ด๊ฐ€๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  ๊ฐ์ฒด์—์„œ ๊ทธ ๋ฉ”์„œ๋“œ๋“ค์„ ๋‹ค ํ™œ์šฉํ•˜๋ฉด ์ƒ๊ด€์ด ์—†์ง€๋งŒ

๋ช‡๋ช‡๊ฐœ์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ด๋Ÿฐ๊ฒฝ์šฐ์— ISP์›์น™์„ ์œ„๋ฐ˜ํ–ˆ๋‹ค๊ณ  ๋ณด๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ์—๋Š”, ํ”„๋กœํ† ์ฝœ ๋ญ‰์น˜๋ฅผ ๋”์šฑ ์ƒ์„ธํ•˜๊ฒŒ ๋ถ„๋ฆฌํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค !

ํ”„๋กœํ† ์ฝœ์„ ๊ฒฝ์šฐ์— ๋งž๊ฒŒ ๋ถ„๋ฆฌํ•œ๋‹ค๋ฉด, ๋‚ญ๋น„ํ•˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์—†๊ฒŒ ๋˜๊ฒ ์ฃ  !

 

๋‚˜์œ ์˜ˆ์‹œ 

protocol Shape {
    var area: Float { get }
    var length: Float { get }
}

class Square: Shape {
    var width: Float
    var height: Float
    
    var area: Float {
        return width * height
    }
    
    var length: Float {
        return 0
    }
    
    init(width: Float,
         height: Float) {
        self.width = width
        self.height = height
    }
}

class Line: Shape {
    var pointA: Float
    var pointB: Float
    
    var area: Float {
        return 0
    }
    
    var length: Float {
        return pointA - pointB
    }
    
    init(pointA: Float,
         pointB: Float) {
        self.pointA = pointA
        self.pointB = pointB
    }
}

Line, Square ๋ชจ๋‘ Shape์„ ์ƒ์†๋ฐ›๋Š” ๊ฐ์ฒด์ด์ง€๋งŒ

์‹ค์ œ๋กœ Square๋Š” length๋ผ๋Š” ๋ณ€์ˆ˜๊ฐ€ ํ•„์š”๊ฐ€ ์—†๊ณ 

Line์€ area๋ผ๋Š” ๋ณ€์ˆ˜๊ฐ€ ํ•„์š”์—†๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ์—๋„ ๋‹จ์ง€ Shape์ด๋ผ๋Š” ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ๋‹ค๋Š” ์ด์œ ๋งŒ์œผ๋กœ ํ•„์š”์—†๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ด๋Ÿฐ ๊ฒฝ์šฐ์— ISP์˜ ์›์น™์„ ์ง€ํ‚ค์ง€ ์•Š๊ณ  ์žˆ๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋ถˆํ•„์š”ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด ํ”„๋กœํ† ์ฝœ์„ ๋” ์ƒ์„ธํžˆ ๋ถ„๋ฆฌํ•˜๋Š”๊ฒŒ ์ข‹๊ฒ ์ฃ  !

 

์ข‹์€ ์˜ˆ์‹œ 

protocol AreaCalculatableShape {
    var area: Float { get }
}

protocol LenghtCalculatableShape {
    var length: Float { get }
}

class Square: AreaCalculatableShape {
    var width: Float
    var height: Float
    
    var area: Float {
        return width * height
    }
    
    init(width: Float,
         height: Float) {
        self.width = width
        self.height = height
    }
}

class Line: LenghtCalculatableShape {
    var pointA: Float
    var pointB: Float
    
    var length: Float {
        return pointA - pointB
    }
    
    init(pointA: Float,
         pointB: Float) {
        self.pointA = pointA
        self.pointB = pointB
    }
}

๊ธฐ์กด์— ํ•„์š”์—†๋Š” ๊ธฐ๋Šฅ๋“ค์„ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๋˜ ์ธํ„ฐํŽ˜์ด์Šค๋“ค์„ ๋”์šฑ ์„ธ๋ถ„ํ™”ํ•˜์—ฌ ๋‚˜๋ˆ„์–ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

 

AreaCalculatableShape, LenghtCalculatableShape์œผ๋กœ ๊ฐ๊ฐ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์„ธ๋ถ„ํ™”์‹œ์ผœ

๋„“์ด๋ฅผ ๊ตฌํ•ด์•ผํ•˜๋Š” Shape์—๋งŒ AreaCalculatableShape ์ฑ„ํƒํ•˜์—ฌ ๊ตฌํ˜„ํ•˜๊ณ 

๊ธธ์ด๋ฅผ ๊ตฌํ•ด์•ผํ•˜๋Š” Shape์—๋งŒ LenghtCalculatableShape ์ฑ„ํƒํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๊ฐ๊ฐ ํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์—†๊ฒŒ ๋˜์ฃ  !

 

๊ฐ๊ฐ์„ ISP์˜ ์›์น™์„ ์ง€ํ‚ค๋Š” ํ”„๋กœ๊ทธ๋žจ์˜ ์„ค๊ณ„๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ISP์˜ ํ•ต์‹ฌ์€ ํ”„๋กœํ† ์ฝœ์˜ ๋ถ„๋ฆฌ๋ผ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค !

 

 

 


 

 

 

5. DIP(Dependency Inversion Principle) - ์˜์กด๊ด€๊ณ„ ์—ญ์ „ ์›์น™

 

์ƒ์œ„ ๋ชจ๋“ˆ์ด ํ•˜์œ„ ๋ชจ๋“ˆ์— ์˜์กดํ•˜๋ฉด ์•ˆ๋˜๊ณ  ๋‘ ๋ชจ๋“ˆ ๋ชจ๋‘ ์ถ”์ƒํ™”์— ์˜์กดํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค๋Š” ์›์น™

 

ํด๋ž˜์Šค ์‚ฌ์ด์—๋Š” ์˜์กด๊ด€๊ณ„๊ฐ€ ์กด์žฌํ•  ์ˆ˜ ๋ฐ–์— ์—†์Šต๋‹ˆ๋‹ค! 

์˜์กด ๊ด€๊ณ„๊ฐ€ ์กด์žฌํ•˜๋˜, ์ง์ ‘์ ์œผ๋กœ ๊ตฌ์ฒด์ ์ธ ํด๋ž˜์Šค๋ผ๋ฆฌ ์˜์กดํ•˜์ง€ ๋ง๊ณ 

๊ทธ ์‚ฌ์ด์— ์ตœ๋Œ€ํ•œ ์ถ”์ƒํ™”๋œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ™œ์šฉํ•ด ์˜์กดํ•˜๋ผ๋Š” ๊ฒƒ์ด DIP ์›์น™์ž…๋‹ˆ๋‹ค !

 

์ƒ์œ„ ๋ชจ๋“ˆ์ด ํ•˜์œ„๋ชจ๋“ˆ์— ์˜์กดํ•˜๋ฉด ์•ˆ๋œ๋‹ค๋Š” ๋ง์ด ์ง์ ‘์ ์œผ๋กœ ์˜์กดํ•˜์ง€ ๋ง๋ผ๋Š” ๋ง ! 

 

์ถ”์ƒํ™”๋ฅผ ์ง„ํ–‰ํ•˜์—ฌ ๊ฐ๊ฐ์˜ ๋ชจ๋“ˆ์— ๋” ์ถ”์ƒํ™”๋œ ๊ฒƒ์— ์˜์กดํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์•ผํ•œ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค. 

์ด๋ ‡๊ฒŒ ์ฝ”๋“œ๋ฅผ ์„ค๊ณ„ํ•ด์•ผ ์žฌ์‚ฌ์šฉ์—๋„ ์œ ์šฉํ•˜๊ณ  ํ•˜๋‚˜๋ฅผ ์ˆ˜์ •ํ•˜๋”๋ผ๋„ ๋‹ค๋ฅธ ์ˆ˜์ •์‚ฌํ•ญ์ด 

๋งŽ์ด ์—†๋Š” ์ข‹์€ ํ”„๋กœ๊ทธ๋žจ์„ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

DIP ์›์น™์€ ๋‚˜์ค‘์— Unit Test๋ฅผ ์ง„ํ–‰ํ•  ๋•Œ ๋”์šฑ ์ค‘์š”ํ•˜๊ฒŒ ๋  ์›์น™์ธ๋ฐ 

์˜์กด์„ฑ ์ฃผ์ž…์ด๋ผ๋Š” ๊ฐœ๋…์ด ๋‚˜์˜ต๋‹ˆ๋‹ค !.

 

์ƒ์œ„ ๋ชจ๋“ˆ์— ์–ด๋–ค ํ•˜์œ„ ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•  ๋•Œ, ์ƒ์œ„๋ชจ๋“ˆ์—์„œ ์ง์ ‘์ ์œผ๋กœ 

ํ•˜์œ„๋ชจ๋“ˆ์„ ์ดˆ๊ธฐํ™”ํ•˜์ง€ ์•Š๊ณ  ์™ธ๋ถ€์—์„œ ํ•˜์œ„๋ชจ๋“ˆ์„ ์ดˆ๊ธฐํ™” ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋ผ๋Š” ๋œป์ž…๋‹ˆ๋‹ค !

๊ทธ๋ฆฌ๊ณ  ์ด ์ƒ์œ„ ๋ชจ๋“ˆ, ํ•˜์œ„๋ชจ๋“ˆ์„ ๋ชจ๋‘ ์ถ”์ƒํ™”๋œ ๊ฐ์ฒด์— ์˜์กดํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

 

๋‚˜์œ์˜ˆ์‹œ 

class APIHandler {
    func request() -> Data {
        return Data(base64Encoded: "This Data")!
    }
}

class LoginService {
    let apiHandler: APIHandler = APIHandler()
    
    func login() {
        let loginData = apiHandler.request()
        print(loginData)
    }
}

ํ˜„์žฌ ์ƒ์œ„๋ชจ๋“ˆ์ธ LoginService๊ฐ€ ํ•˜์œ„ ๋ชจ๋“ˆ์ธ APIHandler์— ์˜์กดํ•˜๊ณ  ์žˆ๋Š” ๊ด€๊ณ„๋กœ

๋งŒ์•ฝ  APIHandler์˜ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์ด ๋ณ€ํ™”ํ•˜๊ฒŒ ๋˜๋ฉด ํ”„๋กœ๊ทธ๋žจ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๊ฒŒ ๋˜๊ณ 

์ƒˆ๋กญ๊ฒŒ LoginService๋ผ๋Š” ์ƒ์œ„๋ชจ๋“ˆ์„ ์ˆ˜์ •ํ•ด์•ผํ•˜๋Š” ์ƒํ™ฉ์ด ์ผ์–ด๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ง์ ‘ APIHandler ํด๋ž˜์Šค๋ฅผ ๊ฐ€์ ธ์™€์„œ ์˜์กด์„ ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ Handler๊ฐ€ ๋“ค์–ด์˜ค๋Š” ๊ฒฝ์šฐ? 

์ง์ ‘ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ์ถ”๊ฐ€ํ•  ์ผ์ด ๋งŽ๊ธฐ ๋•Œ๋ฌธ ! 

๋ณ€ํ™”์— ๋งค์šฐ ์ทจ์•ฝํ•œ ๊ตฌ์กฐ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.. 

 

์ด๋Ÿฌํ•œ ์ƒํ™ฉ์ด DIP์˜ ์›์น™์„ ์–ด๊ธด ํ”„๋กœ๊ทธ๋žจ์˜ ์„ค๊ณ„๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ด๋ฅผ ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•ด ์˜์กด์„ฑ ์ฃผ์ž…์ด๋ผ๋Š” ๊ฒƒ์„ ์‚ฌ์šฉํ•ด์„œ ์ˆ˜์ •ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค 

(DIP๋ฅผ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์˜์กด์„ฑ์„ ์—ญ์ „์‹œํ‚ค๊ธฐ.)

 

์ข‹์€ ์˜ˆ์‹œ 

 

protocol APIHandlerProtocol {
    func requestAPI() -> Data
}

class LoginService {
    let apiHandler: APIHandlerProtocol
    
    init(apiHandler: APIHandlerProtocol) {
        self.apiHandler = apiHandler
    }
    
    func login() {
        let loginData = apiHandler.requestAPI()
        print(loginData)
    }
}

class LoginAPI: APIHandlerProtocol {
    func requestAPI() -> Data {
        return Data(base64Encoded: "User")!
    }
}

let loginAPI = LoginAPI()
let loginService = LoginService(apiHandler: loginAPI)
loginService.login()

์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•˜๊ฒŒ ๋˜๋ฉด LoginService๋Š” ๊ธฐ์กด์— APIHandler์— ์˜์กดํ•˜์ง€ ์•Š๊ณ 

์ถ”์ƒํ™” ์‹œํ‚จ ๊ฐ์ฒด์ธ APIHandlerProtocol์— ์˜์กดํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— APIHandlerProtocol์˜ ๊ตฌํ˜„๋ถ€๋Š” ์™ธ๋ถ€์—์„œ ๋ณ€ํ™”์— ๋”ฐ๋ผ ์ง€์ •ํ•ด์„œ ์ง€์ •ํ•ด์ฃผ๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์— 

LoginService๋Š” ๊ตฌํ˜„๋ถ€์— ์ƒ๊ด€์—†์ด ์ข€ ๋” ๋ณ€ํ™”์— ๋ฏผ๊ฐํ•˜์ง€ ์•Š์€ 

DIP์˜ ์›์น™์„ ์ง€ํ‚จ ํ”„๋กœ๊ทธ๋žจ์„ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

( ํ”„๋กœํ† ์ฝœ ๊ตฌํ˜„๋ถ€๋Š” ์™ธ๋ถ€์—์„œ ์ฒ˜๋ฆฌํ•ด์ค€ ๋‹ค์Œ, ๋กœ๊ทธ์ธ ์„œ๋น„์Šค๋ผ๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค ๋•Œ

์˜์กด์„ฑ ์ฃผ์ž…์„ ์ฒ˜๋ฆฌํ•ด ์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ๋ณด๋‹ค ์œ ์—ฐํ•œ ๊ตฌ์กฐ๋กœ ์ฝ”๋“œ ์ž‘์„ฑ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. )

 

์ด๋ ‡๊ฒŒ ์™ธ๋ถ€์—์„œ ๋‚ด๋ถ€์˜ ๋ณ€์ˆ˜๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด์„œ ์˜์กด๊ด€๊ณ„๋ฅผ ๊ฐ€์ง€๋Š” ๊ฒฝ์šฐ๋ฅผ ์˜์กด์„ฑ ์ฃผ์ž…์ด๋ผ๊ณ  ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด ๋•Œ, ์˜์กด์„ฑ ์ฃผ์ž…์„ ์ถ”์ƒํ™”์‹œ์ผœ ์ง„ํ–‰ํ•˜๊ฒŒ ๋˜๋ฉด ๋”์šฑ ๋ณ€ํ™”์—๋Š” ์•ˆ์ „ํ•œ ํ”„๋กœ๊ทธ๋žจ์„ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

protocol APIHandlerProtocol {
    func requestAPI()
}

class getHandler: APIHandlerProtocol {
    func requestAPI() {
        print("getHandler")
    }
}

class postHandler: APIHandlerProtocol {
    func requestAPI() {
        print("postHandler")
    }
}

class putHandler: APIHandlerProtocol {
    func requestAPI() {
        print("putHandler")
    }
}

class APIService {
    var apiHandler: APIHandlerProtocol

    init(handlerType: APIHandlerProtocol) {
        apiHandler = handlerType
    }
    
    func requestAPIByHandler() {
        apiHandler.requestAPI()
    }
}

import UIKit

class ViewController: UIViewController {


    override func viewDidLoad() {
        super.viewDidLoad()
        let someService = APIService(handlerType: getHandler())
        someService.requestAPIByHandler()
        
        someService.apiHandler = putHandler()
        someService.requestAPIByHandler()
    }
}

์•ž์„œ ๋ณด์—ฌ๋“œ๋ฆฐ ์ฝ”๋“œ์—์„œ๋„ ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ•ด์ฃผ๋Š” ๋ถ€๋ถ„์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค !

์ด์ฒ˜๋Ÿผ 5๊ฐ€์ง€์˜ ์›์น™์ด ์„œ๋กœ ๊ด€๊ณ„๋ฅผ ๊ฐ–๊ณ  ์žˆ๋Š” ๊ฒƒ๋„ ์žˆ๋‹ค.

ISP๋ฅผ ์ง€ํ‚ค๊ธฐ ์œ„ํ•ด ๊ฒฐ๊ตญ SRP๋ฅผ ์ง€ํ‚ค๊ฒŒ ๋œ๋‹ค๋˜๊ฐ€.. 

 

๊ทธ๋Ÿฌ๋‚˜ ์ด ์›์น™์„ ๋ชจ๋‘ ์ง€ํ‚ค๋ฉด์„œ ํ”„๋กœ๊ทธ๋žจ์„ ์„ค๊ณ„ํ•˜๊ธฐ๋Š” ํž˜๋“ค๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค

๋‹ค๋“ค ๊ทธ๋ ‡๋‹ค๊ณ  ๋งํ•˜๊ธฐ๋„ ํ•˜๊ณ ,, ํ•˜์ง€๋งŒ ์ด๊ฑธ ๊ณต๋ถ€ํ•˜๋ฉด์„œ, ์–ด๋–ค๊ฒŒ ๋‚˜์œ ์ฝ”๋“œ์ด๊ณ  ์–ด๋–ค๊ฒŒ ์ข‹์€ ์ฝ”๋“œ์ธ์ง€

ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค ๋„˜ ์ข‹์•˜๋‹ค !! 

 

 

 

 

 

 

 

์˜ˆ์‹œ ์ฝ”๋“œ ์ฐธ๊ณ  

 

[SWIFT] Swift SOLID ์›์น™

์•ˆ๋…•ํ•˜์„ธ์š” ์˜ค๋Š˜์€ SOLID ์›์น™์— ๋Œ€ํ•ด ์ •๋ฆฌ๋ฅผ ํ•ด๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๊ทผ๋ฐ, ์ด๊ฒƒ์„ Swift ์–ธ์–ด์— ์ ‘๋ชฉ์‹œ์ผœ์„œ ์ดํ•ดํ•ด๋ณด๊ณ  ์ž‘์„ฑํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค ๐Ÿ™Œ SOLID๋ž€? SOLID ์›์น™์ด๋ž€ ๊ฐ์ฒด์ง€ํ–ฅ ์„ค๊ณ„์— ๋” ์ข‹์€ ์•„ํ‚คํ…์ณ

dongminyoon.tistory.com

 

์Šค์œ„ํ”„ํŠธ๋กœ ๋‹ค์‹œ๋ณด๋Š” ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ: ํ”ผํ•ด์•ผํ•  ์ฝ”๋”ฉ ์Šต๊ด€ ยท Soojin Ro

๋ฐฐ๊ฒฝ ์ปดํ“จํ„ฐ์™€ ํšŒํ™”(painting)๋ฅผ ์ „๊ณตํ–ˆ๊ณ  ๊ฝค ์„ฑ๊ณตํ•œ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ํ”„๋กœ๊ทธ๋ž˜๋จธ๋Š” ๊ณผํ•™์ž๋ณด๋‹ค ํ™”๊ฐ€์™€ ๊ณตํ†ต์ ์ด ๋” ๋งŽ๋‹ค๊ณ  ํ–ˆ๋‹ค. ์ •๋ง๋กœ, ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์ž˜ํ•˜๋ ค๋Š” ๋…ธ๋ ฅ์„ ํ•˜๋‹ค๋ณด๋ฉด ๊ณผํ•™๋ณด๋‹ค๋Š” ๊ฒฝํ—˜์ ์œผ

soojin.ro

 

[Design-Pattern-In-Swift] 1. SOLID ์›์น™์„ Swift ์ฝ”๋“œ์— ์ ์šฉํ•ด๋ณด๊ธฐ

GoF์˜ ๋””์ž์ธํŒจํ„ด์ด๋ผ๋Š” ์ฑ…์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋””์ž์ธ ํŒจํ„ด์— ๋Œ€ํ•ด ๊ณต๋ถ€๋ฅผ ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค! ํ”„๋กœ์ ํŠธ์—์„œ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋ฐœ์ƒํ•˜๋Š” ๋‹ค์–‘ํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ ๋ฐฉ๋ฒ•์„ ๊ตฌ์กฐํ™” ์‹œํ‚จ๊ฒƒ์ด ๋””์ž์ธ ํŒจ

i-colours-u.tistory.com

 

Comments