Factory Pattern in swift

pcsoyeon·2021년 11월 24일
0

참고자료
Design Patterns in Swift #1: Factory Method and Singleton

Factory Pattern

팩토리 또는 팩토리 메서드 패턴은 생성 디자인 패턴의 일종으로, 인스턴스 생성을 팩토리 타입의 메서드에 위임하는 방식으로 개발자들에게 이용하는 타입에 대한 정보를 숨기고 인스턴스 생성을 용이하게 해준다.

Factory Pattern in swift

팩토리 패턴을 사용하면 클래스 생성자를 직접 호출하지 않고 팩토리 메서드가 인스턴스화 하는 클래스를 만들 수 있고 클래스 계층에 대해서 전혀 알지 못해도 매우 유용한 객체를 만들 수 있다. (You get a lot of bang for cheap.) 최소한의 코드로 기능 및 UI를 구현할 수 있다.

예를 들어 디자인 팀이 앱 배경 이미지로 사용하기 위해서 app theming code를 선택했다고 가정해보자.

let defaultHeight = 200
let defaultColor = UIColor.blue
 
protocol HelperViewFactoryProtocol {
    
    func configure()
    func position()
    func display()
    var height: Int { get }
    var view: UIView { get }
    var parentView: UIView { get }
    
}

먼저, 기존의 뷰 컨트롤러 안에서 도형을 그리기 위한 프로토콜을 만들어보자. 다양한 용도로 사용할 수 있으므로 접근 수준은 공개로 설정한다.

UIView는 기본적으로 직사각형 프레임을 갖고 있기 때문에 base shape class를 Square로 설정하는 것이 편하다.

class Square: HelperViewFactoryProtocol {
    let height: Int
    let parentView: UIView
    var view: UIView
    
    init(height: Int = defaultHeight, parentView: UIView) {
        self.height = height
        self.parentView = parentView
        view = UIView()
    }
    
    func configure() {
        let frame = CGRect(x: 0, y: 0, width: height, height: height)
        view.frame = frame
        view.backgroundColor = defaultColor
    }
    
    func position() {
        view.center = parentView.center
    }

    func display() {
        configure()
        position()
        parentView.addSubview(view)
    }
}

코드를 재사용하고 있으므로 계층 구조를 단순하게 유지 관리할 수 있다. 원과 직사각형 클래스는 베이스 클래스인 사각형 클래스를 구체화한 것이다.

class Circle : Square {
    override func configure() {
        super.configure()
        
        view.layer.cornerRadius = view.frame.width / 2
        view.layer.masksToBounds = true
    }
    
}

class Rectangle : Square {
    override func configure() {
        let frame = CGRect(x: 0, y: 0, width: height + height/2, height: height)
        view.frame = frame
        view.backgroundColor = UIColor.blue
    }
    
}

(하나의 파일에서 관리하는 경우 fileprivate 키워드를 통해 팩토리 메서드의 목적 중 하나인 복잡성을 숨길 수 있다.)

객체 생성을 추상적이고 간단하게 만드는 factory method 코드는 다음과 같다.

import UIKit

enum Shapes {
    case square
    case circle
    case rectangle
}

class ShapeFactory {
    let parentView: UIView
    
    init(parentView: UIView) {
        self.parentView = parentView
    }
    
    func create(as shape: Shapes) -> HelperViewFactoryProtocol {
        switch shape {
        case .square:
            let square = Square(parentView: parentView)
            return square
        case .circle:
            let circle = Circle(parentView: parentView)
            return circle
        case .rectangle:
            let rectangle = Rectangle(parentView: parentView)
            return rectangle
        }
    }
}

위와 같이 팩토리를 구현했다면 실질적으로 도영을 그리기 위한 두가지 메서드를 다음과 같이 구현할 수 있다.

func createShape(_ shape: Shapes, on view: UIView) {
    let shapeFactory = ShapeFactory(parentView: view)
    shapeFactory.create(as: shape).display()
    
}

func getShape(_ shape: Shapes, on view: UIView) -> HelperViewFactoryProtocol {
    let shapeFactory = ShapeFactory(parentView: view)
    return shapeFactory.create(as: shape)
}

마지막으로 뷰 컨트롤러에서 사용자의 인터랙션에 따라서 팩토리 패턴을 통해 상황에 맞는 피드백을 주면 된다.

import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let _ = Client(brand: .nike)
    }
    
    @IBAction func drawCircle(_ sender: Any) {
        createShape(.circle, on: view)
    }
    
    @IBAction func drawSquare(_ sender: Any) {
        createShape(.square, on: view)
        
    }
    
    @IBAction func drawRectangle(_ sender: Any) {
        let rectangle = getShape(.rectangle, on: view)
        rectangle.display()
    }
}
profile
Slowly But Surely

0개의 댓글