VC와 dataLayer는 비즈니스로직을 통해 상호작용한다

임혜정·2024년 9월 16일
0
post-custom-banner

VC와 dataLayer는 비즈니스 로직을 통해 상호작용한다.
각 계층의 책임을 분리하고 코드의 재사용성과 유지보수성을 기대할 수 있다
피치못할 엄청난 자연재해(업데이트 1시간전이라거나?)로인해 crud저장 역할을 하는 manager나 vc에 다른 기능과 한 메서드에 비즈니스 로직까지 때려박게되기도 하는데 이럴 경우, 다른 vc에서 같은 기능의 메서드가 필요할 때 재사용이 어려울 수 있다.

지금 진행중인 프로젝트의 경우 데이터와 관련하여 coredata를 주로 사용하는데
dataLayer는 CRUD 저장소인 DataManager 같은 것이 될 수 있다.

import CoreData

class DataManager {
    static let shared = DataManager()
    
    private init() {}
    
    lazy var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "MyDataModel")
        container.loadPersistentStores { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        }
        return container
    }()
    
    // Create
    func createItem(name: String) -> Item? {
        let context = persistentContainer.viewContext
        let item = Item(context: context)
        item.name = name
        item.createdAt = Date()
        
        do {
            try context.save()
            return item
        } catch {
            print("Failed to create item: \(error)")
            return nil
        }
    }
    
    // Read
    func fetchItems() -> [Item] {
        let context = persistentContainer.viewContext
        let fetchRequest: NSFetchRequest<Item> = Item.fetchRequest()
        
        do {
            return try context.fetch(fetchRequest)
        } catch {
            print("Failed to fetch items: \(error)")
            return []
        }
    }
    
    // Update
    func updateItem(_ item: Item, newName: String) -> Bool {
        let context = persistentContainer.viewContext
        item.name = newName
        
        do {
            try context.save()
            return true
        } catch {
            print("Failed to update item: \(error)")
            return false
        }
    }
    
    // Delete
    func deleteItem(_ item: Item) -> Bool {
        let context = persistentContainer.viewContext
        context.delete(item)
        
        do {
            try context.save()
            return true
        } catch {
            print("Failed to delete item: \(error)")
            return false
        }
    }
}

매니저는 싱글톤으로 제작하여 불변성을 확보하고 crud에만 충실하도록 한다
그리고

class BusinessService {
    private let dataManager = DataManager.shared
    
    func createNewItem(name: String) -> Bool {
        guard !name.isEmpty else { return false }
        return dataManager.createItem(name: name) != nil
    }
    
    func getAllItems() -> [Item] {
        return dataManager.fetchItems()
    }
    
    func updateItemName(_ item: Item, newName: String) -> Bool {
        guard !newName.isEmpty else { return false }
        return dataManager.updateItem(item, newName: newName)
    }
    
    func removeItem(_ item: Item) -> Bool {
        return dataManager.deleteItem(item)
    }
}

비즈니스 로직만을 담는 서비스 모델을 따로 제작하여 이로서 manager와 상호작용한다.

요청 흐름:
VC (View Controller) -> Logic (Business Logic) -> Manager (Data Manager)
응답 흐름:
Manager (Data Manager) -> Logic (Business Logic) -> VC (View Controller)

이렇게 정하므로서 또한 좋은 점은 내 파트가 아닌 부분에 대해서도 어느 파일에 있을지 대충 파악할 수가 있다

dto

만약 DTO (Data Transfer Object)를 도입하면 아키텍처가 VC > DTO > Service > Manager 구조로 확장될 수 있다.

VC (View Controller): 사용자 인터페이스를 관리한다.
DTO (Data Transfer Object): 계층 간 데이터 전송을 위한 객체다.
Service: 비즈니스 로직을 처리한다. (이전의 BusinessLogic과 유사한 역할)
Manager: 데이터 저장소와의 직접적인 상호작용을 담당

profile
오늘 배운걸 까먹었을 미래의 나에게..⭐️
post-custom-banner

0개의 댓글