Swift - Usecase

Marble·2025년 1월 8일

Clean Architecture

목록 보기
3/5

이번 글에서는 유즈케이스에 대해 작성해보겠습니다.

UseCase

유즈케이스는 시스템이 사용자와 상호작용하는 방식을 설명하는 방법입니다. 이는 특정 목표를 달성하기 위해 사용자가 시스템과 어떻게 상호작용하는지를 정의합니다. 유즈케이스는 주로 사용자의 요구사항을 이해하고, 시스템의 기능을 명확히 하는 데 도움을 줍니다. 각 유즈케이스는 하나의 비즈니스 로직을 담고 있습니다. 예를 들어, 사용자 등록, 로그인, 주문 처리 등의 기능이 포함됩니다.

구성 요소

유즈케이스는 일반적으로 다음과 같은 요소로 구성됩니다

  • 행위자(Actor)
    시스템과 상호작용하는 사용자 또는 다른 시스템을 나타내며, 유즈케이스가 해결하고자 하는 문제의 주체입니다.
    ex) 일반 사용자, 관리자, 외부 시스템 등
  • 시나리오(Scenario)
    행위자가 시스템과 상호작용하는 과정이며, 성공 경로와 실패 경로를 모두 포함할 수 있습니다.
    ex) 사용자가 로그인하는 과정, 상품을 검색하는 과정 등
  • 목표(Goal)
    행위자가 달성하고자 하는 목표로 유즈케이스는 이 목표를 충족하기 위해 설계됩니다.
    ex) 사용자가 계정을 생성하거나 주문을 완료하는 것

Repository 패턴을 예로 들면, Repository로부터 얻은 행위자(도메인)로 시나리오(비즈니스 로직)를 진행하여 목표를 충족한다고 생각합니다.

예시 코드

다음은 이해를 돕기 위한 제품 주문 생성을 위한 유즈케이스 코드입니다.

  1. 도메인 모델 정의
    먼저, 기본적인 도메인 모델인 Product와 Order를 정의합니다.
struct Product {
    let id: Int
    let name: String
    let price: Double
}

struct Order {
    let id: Int
    let products: [Product]
    let totalAmount: Double
}
  1. 리포지토리 프로토콜 정의
    주문과 상품에 대한 데이터 접근을 위한 리포지토리 프로토콜을 정의합니다.
protocol ProductRepository {
    func getProduct(by id: Int) -> Product?
}

protocol OrderRepository {
	func getOrdersCount() -> Int
    func saveOrder(_ order: Order)
}
  1. 리포지토리 구현 클래스
    리포지토리 인터페이스를 구현하는 클래스를 작성합니다.
class InMemoryProductRepository: ProductRepository {
    private var products: [Int: Product] = [
        1: Product(id: 1, name: "상품 A", price: 100.0),
        2: Product(id: 2, name: "상품 B", price: 200.0)
    ]

    func getProduct(by id: Int) -> Product? {
        return products[id]
    }
}

class InMemoryOrderRepository: OrderRepository {
    private var orders: [Order] = []

	func getOrdersCount() -> Int {
        return orders.count
    }

    func saveOrder(_ order: Order) {
        orders.append(order)
        print("주문이 저장되었습니다: \(order)")
    }
}
  1. 유즈케이스 클래스 구현
    주문 생성을 처리하는 유즈케이스 클래스를 정의합니다.
class CreateOrderUseCase {
    private let productRepository: ProductRepository // DIP 원칙
    private let orderRepository: OrderRepository

    init(productRepository: ProductRepository, orderRepository: OrderRepository) {
        self.productRepository = productRepository
        self.orderRepository = orderRepository
    }

    func execute(productIds: [Int]) {
        var orderedProducts: [Product] = []
        var totalAmount: Double = 0.0

        for productId in productIds {
            if let product = productRepository.getProduct(by: productId) {
                orderedProducts.append(product)
                totalAmount += product.price
            } else {
                print("상품 ID \(productId)는 유효하지 않습니다.")
            }
        }

        if !orderedProducts.isEmpty {
            let orderCount = orderRepository.getOrdersCount()
            let order = Order(id: orderCount + 1, products: orderedProducts, totalAmount: totalAmount)
            orderRepository.saveOrder(order)
        } else {
            print("주문할 상품이 없습니다.")
        }
    }
}
  1. 사용
let productRepository: ProductRepository = InMemoryProductRepository()
let orderRepository: OrderRepository = InMemoryOrderRepository()
let createOrderUseCase = CreateOrderUseCase(productRepository: productRepository, orderRepository: orderRepository)

// 주문 생성
createOrderUseCase.execute(productIds: [1, 2]) // 상품 A와 상품 B를 주문
createOrderUseCase.execute(productIds: [3])    // 유효하지 않은 상품 ID

/*
출력 결과:
주문이 저장되었습니다: Order(id: 1, products: [Product(id: 1, name: "상품 A", price: 100.0), Product(id: 2, name: "상품 B", price: 200.0)], totalAmount: 300.0)
상품 ID 3는 유효하지 않습니다.
주문할 상품이 없습니다.
*/

위의 코드를 요약하면 도메인 모델인 Product와 Order를 정의하여 상품과 주문의 속성을 나타내고 리포지토리를 정의하여 상품과 주문을 관리합니다. 이후 유즈케이스를 통해 상품 ID를 받아 주문을 생성하는 비즈니스 로직을 구현합니다.

profile
개발자가 되고 싶은 공돌이

0개의 댓글