[EasyCloset] ๐Ÿž๏ธ ์ด๋ฏธ์ง€ ๊ด€๋ จ Repository Protoco๋ถ„๋ฆฌ, POP ๊ตฌํ˜„

Mason Kimยท2023๋…„ 6์›” 23์ผ
0

EasyCloset ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…

๋ชฉ๋ก ๋ณด๊ธฐ
4/5

์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์™€์„œ ๋ชจ๋ธ ๊ฐ์ฒด์— ๋งคํ•‘ํ•˜๋Š” ์—ญํ• ์„ POP๋กœ ๊ตฌํ˜„

๋ฐฐ๊ฒฝ

image
  • StyleRepository ๋ฅผ ๊ตฌํ˜„ํ•˜๋˜ ์ค‘, Style ๋“ค์„ ๊ฐ€์ ธ์˜ฌ ๋•Œ ๊ฐ ์Šคํƒ€์ผ ๋‚ด๋ถ€์— ์žˆ๋Š” Clothes ๊ฐ์ฒด์— "์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์™€์„œ ๋งคํ•‘"ํ•˜๋Š” ์ž‘์—…์ด ๋˜‘๊ฐ™์ด ํ•„์š”ํ–ˆ์Œ

    Q. StyleRepository๊ฐ€ ClothesRepository์—์„œ ๋ฐ์ดํ„ฐ๋ฅด ๊ฐ€์ ธ์˜ค๋ฉด ๋˜๋Š” ๊ฒƒ ์•„๋‹Œ๊ฐ€?
    - A. ์กฐ๊ธˆ ๋น„ํšจ์œจ์ ์ธ ๋ฉด์ด ์กด์žฌํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์‚ฌ์šฉ๋˜๋Š” Scene์ด ์ „ํ˜€ ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ๊ฐ์˜ Repository๊ฐ€ ๋ณ„๊ฐœ๋กœ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์ด ๋” ์ ์ ˆํ•˜๊ฒ ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๊ธฐ์— ๋ณ„๋„๋กœ ๊ตฌํ˜„ํ•จ. (ex. Clothes์„ ํ™•์ธํ•˜์ง€ ์•Š๊ณ , Styleํ™”๋ฉด๋งŒ ๋ณผ ์ˆ˜๋„ ์žˆ๊ธฐ์—...)

  • ์ด๋ฏธ์ง€๋ฅผ ๋งคํ•‘ํ•˜๋Š” ๋กœ์ง์„ ํ”„๋กœํ† ์ฝœ๋กœ ์ถ”์ƒํ™”ํ•˜์—ฌ POP๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ๋กœ ๊ฒฐ์ •

ImageFetchable POP ๊ตฌํ˜„

  • ์•„๋ž˜์ฒ˜๋Ÿผ ์ด๋ฏธ์ง€๋ฅผ ๋งคํ•‘ ํ•ด ์ฃผ๋Š” ๋ถ€๋ถ„์„ protocol extension ์œผ๋กœ ๊ตฌํ˜„ํ•จ.
    • ํ•˜์ง€๋งŒ ์ด๋Ÿฐ ๋ฐฉ์‹์€ ์˜ค์ง Clothes ์—๋งŒ ์ด๋ฏธ์ง€๋ฅผ ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์ด๋ฏธ์ง€๋ฅผ ๋งคํ•‘ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” protocol ํƒ€์ž…์„ ์ •์˜ํ•˜์—ฌ ์ œ๋„ค๋ฆญ์œผ๋กœ ์ฐจํ›„ ๋‹ค๋ฅธ ๋ชจ๋ธ ๊ฐ์ฒด๋“ค๋„ ์ด๋ฏธ์ง€๋ฅผ ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๊ณ  ์‹ถ์—ˆ์Œ
    • โ†’ ์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ ํ•„์š”ํ•œ ์ •๋ณด๋Š” id๊ฐ’๊ณผ image ํ”„๋กœํผํ‹ฐ ๋‘ ๊ฐ€์ง€๋งŒ ํ•„์š”ํ•˜๊ธฐ์— ํ•ด๋‹น ๋ถ€๋ถ„์„ protocol ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ์—ฌ๋Ÿฌ ๋ชจ๋ธํƒ€์ž…์— ์ด๋ฏธ์ง€๋ฅผ ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๊ตฌํ˜„ํ•˜๊ธฐ๋กœ ๊ฒฐ์ •
protocol ImageFetchable {
  var imageCacheManager: ImageCacheManager { get }
  var imageFileStorage: ImageFileStorageProtocol { get }
  func addingImages(to clothesModels: [Clothes]) -> AnyPublisher<[Clothes], Never>
}

extension ImageFetchable {
  var imageCacheManager: ImageCacheManager { .shared }
  var imageFileStorage: ImageFileStorageProtocol { ImageFileStorage.shared }

  func addingImages(to clothesModels: [Clothes]) -> AnyPublisher<[Clothes], Never> {
    let clothesWithImagePublishers: [AnyPublisher<Clothes, Never>] = clothesModels.map { model in
      if let image = imageCacheManager.get(for: model.id) {
        var clothes = model
        clothes.image = image
        return Just(clothes).eraseToAnyPublisher()
      }

      return imageFileStorage.load(withID: model.id)
        .replaceError(with: UIImage())
        .map { image in
          var clothes = model
          clothes.image = image
          return clothes
        }
        .eraseToAnyPublisher()
    }

    return Publishers.MergeMany(clothesWithImagePublishers)
      .collect()
      .eraseToAnyPublisher()
  }
}

์ตœ์ข… ๊ตฌํ˜„ - ์—ฌ๋Ÿฌ ํƒ€์ž…์— ์ด๋ฏธ์ง€๋ฅผ ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๊ตฌํ˜„

  • ์ด๋ฏธ์ง€๋ฅผ ๋งคํ•‘ํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ํ”„๋กœํผํ‹ฐ์ธ id, image๋งŒ ๋ถ„๋ฆฌํ•˜์—ฌ ImagableModel ์ด๋ผ๋Š” ํ”„๋กœํ† ์ฝœ๋กœ ์ถ”์ƒํ™”
protocol ImagableModel {
  var id: UUID { get }
  // ์ด๋ฏธ์ง€๋ฅผ ๋งคํ•‘ํ•  ๋•Œ ์ €์žฅํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๋ฏ€๋กœ get set ๋‘˜ ๋‹ค ์š”๊ตฌ์‚ฌํ•ญ์„ ์คŒ
  var image: UIImage? { get set }
}

// ์ด๋ฏธ์ง€๋ฅผ ๋งคํ•‘ํ•  ๋ชจ๋ธ ๊ฐ์ฒด์— ImagbleModel ์ฑ„ํƒ
struct Clothes: ImagableModel {
  let id: UUID
  var image: UIImage?
	...
}
  • ์•„๋ž˜์ฒ˜๋Ÿผ addingImages ๋ฉ”์„œ๋“œ์— ImagableModel๋กœ ์ œ๋„ค๋ฆญ์„ ์คŒ์œผ๋กœ์„œ, ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” (ImagebleModel์„ ์ฑ„ํƒํ•œ) ์–ด๋–ค ํƒ€์ž…์˜ ๋ชจ๋ธ์— ๋Œ€ํ•ด์„œ๋„ ๋งคํ•‘์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋˜์—ˆ์Œ.
    	> ๊ทธ ์™ธ ๋‹ค๋ฅธ ๋ถ€๋ถ„์˜ ๊ตฌํ˜„ ๋กœ์ง์€ ๋™์ผ
protocol ImageFetchableRepository {
  func addingImages<T: ImagableModel>(to imagableModels: [T]) -> AnyPublisher<[T], RepositoryError>
...
  • Repository์—์„œ๋Š” ํ•ด๋‹น ImageFetchable์„ ์ฑ„ํƒํ•˜๊ณ , ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜จ ํ›„ addingImages๋ฅผ ํ˜ธ์ถœ๋งŒ ํ•˜๋ฉด ๋˜๋Š” ๊ฐ„๋‹จํ•œ ๋ฐฉ์‹์ด ๋จ
final class ClothesRepository: ClothesRepositoryProtocol, ImageFetchableRepository {
	func fetchClothesList() -> AnyPublisher<ClothesList, RepositoryError> {
	  let clothesEntities = realmStorage.load(entityType: ClothesEntity.self)
	  let clothesModelsWithoutImage = clothesEntities.map { $0.toModelWithoutImage() }
	  return addingImages(to: clothesModelsWithoutImage)
	    .map { $0.toClothesList() }
	    .eraseToAnyPublisher()
	}
profile
iOS developer

0๊ฐœ์˜ ๋Œ“๊ธ€