기초지식공부/디자인패턴

추상 팩토리(Abstract Factory)

DevBabamba 2019. 6. 28. 10:09
반응형

4. 각 패턴별 이해

4.1. 추상 팩토리(Abstract Factory)

  • 구체적인 클래스를 지정하지 않고 관련성을 갖는 객체들의 집합을 생성하거나 서로 독립적인 객체들의 집합을 생성할 수 있는 인터페이스를 제공
  • 관련성 있는 여러 종류의 객체를 일관된 방식으로 생성하는 경우에 유용

4.1.1. 구조

4.1.2. 참여 객체

  • AbstractFactory: 개념적 제품에 대한 객체를 생성하는 오퍼레이션으로 인터페이스를 정의한다.
    • 실제 팩토리 클래스의 공통 인터페이스
  • ConcreateFactory: 구체적인 제품에 대한 객체를 생성하는 오퍼레이션을 구현한다.
    • AbstractFactory 클래스의 추상 메서드를 오버라이드함
  • AbstractProduct: 개념적 제품 객체에 대한 인터페이스를 정의한다.
    • 제품의 공통 인터페이스 이용
  • ConcreateProduct: 구체적으로 팩토리가 생성할 객체를 정의하고, AbstractProduct 가 정의하고 있는 인터페이스를 구현한다.
    • 구체적인 팩토리 클래스에서 생성되는 제품
  • Client: AbstractFactory 와 AbstractProduct 클래스에 선언된 인터페이스를 사용한다.
/*
 해당 코드는 swift로 작성됨.
 ConcreateFactory: 버튼, 모터에 대한 인터페이스를 구상
 ConcreateProduct: 자동차 창문을 올렸다 내리는 버튼과 모터, 간이 엘레베이터를 올리고 내릴 수 있는 버튼과 모터라는 구체적인 제품 클래스
 AbstractFactory: 버튼과 모터를 특정 군에 맞게 생산해 낼 수 있는 인터페이스
 AbstractProduct: 자동차 창문용 제품군, 간이 엘레베이터 제품군을 생산해내는 클래스
 */

// ConcreateFactory1
protocol Button {
    var standard: String { get }
    func up() -> String
    func down() -> String
}

// ConcreateFactory2
protocol Motor {
    var standard: String { get }
    func rotateCounterClockwise() -> String
    func rotateClockwise() -> String
}

// ConcreateProduct 1 A
class CarWindowButton: Button {
    var standard: String

    init() {
        self.standard = "자동차용 창문 버튼"
    }

    func up() -> String {
        return "자동차 창문을 위로 올립니다."
    }

    func down() -> String {
        return "자동차 창문을 아래로 내립니다."
    }

}
// ConcreateProduct 1 B
class ElevatorUpDownButton: Button {
    var standard: String

    init() {
        self.standard = "간이 엘리베이터용 버튼"
    }
    func up() -> String {
        return "간이 엘리베이터를 위로 올립니다."
    }

    func down() -> String {
        return "간이 엘리베이터를 아래로 내립니다."
    }
}

// ConcreateProduct 2 A
class CarWindowMotor: Motor {
    var standard: String

    init() {
        self.standard = "자동차용 창문 모터"
    }

    func rotateCounterClockwise() -> String {
        return "모터가 반시계 방향으로 돌아갑니다."
    }

    func rotateClockwise() -> String {
        return "모터가 시계 방향으로 돌아갑니다."
    }

}

// ConcreateProduct 2 B
class ElevatorMotor: Motor {
    var standard: String

    init() {
        self.standard = "엘리베이터용 모터"
    }

    func rotateCounterClockwise() -> String {
        return "모터가 반시계 방향으로 돌아갑니다."
    }

    func rotateClockwise() -> String {
        return "모터가 시계 방향으로 돌아갑니다."
    }

}

// AbstractFactory
protocol ProductFactory {
    var storage: [Any] {get set}
    func createButton() -> Button
    func createMotor() -> Motor
    func checkProduct()
}

// Abstract Product A
class CarWindowProduct: ProductFactory {
    var storage: [Any] = [Any]()
    func createButton() -> Button {
        let tmpButton = CarWindowButton()
        print("이 버튼의 규격은 \(tmpButton.standard) 이고, up을 누려면 \(tmpButton.up()) 그리고 down을 누르면 \(tmpButton.down())\n")
        storage.append(tmpButton)
        return tmpButton
    }

    func createMotor() -> Motor {
        let tmpMotor = CarWindowMotor()
        print("이 모터의 규격은 \(tmpMotor.standard) 이고, \(tmpMotor.rotateClockwise()) 그리고 \(tmpMotor.rotateCounterClockwise())\n")
        storage.append(tmpMotor)
        return CarWindowMotor()
    }
    func checkProduct() {
        var bCount = 0
        var mCount = 0
        for product in storage {
            switch product {
            case is Button:
                    bCount += 1
                break
            case is Motor:
                    mCount += 1
                break
            default:
                print("unknow product")
            }
        }
        print("버튼은 \(bCount) 개 이고, 모터는  \(mCount) 개 이다.\n")
    }
}

// Abstract Product B
class ElevatorProduct: ProductFactory {
    var storage: [Any] = [Any]()
    func createButton() -> Button {
        let tmpButton = ElevatorUpDownButton()
        print("이 버튼의 규격은 \(tmpButton.standard) 이고, up을 누려면 \(tmpButton.up()) 그리고 down을 누르면 \(tmpButton.down())\n")
        storage.append(tmpButton)
        return tmpButton
    }

    func createMotor() -> Motor {
        let tmpMotor = ElevatorMotor()
        print("이 모터의 규격은 \(tmpMotor.standard) 이고, \(tmpMotor.rotateClockwise()) 그리고 \(tmpMotor.rotateCounterClockwise())\n")
        storage.append(tmpMotor)
        return tmpMotor
    }
    func checkProduct() {
        var bCount = 0
        var mCount = 0
        for product in storage {
            switch product {
            case is Button:
                bCount += 1
                break
            case is Motor:
                mCount += 1
                break
            default:
                print("unknow product")
            }
        }
        print("버튼은 \(bCount) 개 이고, 모터는  \(mCount) 개 이다.\n")
    }
}


let abstractProductA = CarWindowProduct()
let productAButton1 = abstractProductA.createButton()
let productAMotor1 = abstractProductA.createMotor()
let productAButton2 = abstractProductA.createButton()
abstractProductA.checkProduct()

let abstractProductB = ElevatorProduct()
let productBButton1 = abstractProductB.createButton()
let productBMotor1 = abstractProductB.createMotor()
abstractProductB.checkProduct()

/* 결과
 이 버튼의 규격은 자동차용 창문 버튼 이고, up을 누려면 자동차 창문을 위로 올립니다. 그리고 down을 누르면 자동차 창문을 아래로 내립니다.

 이 모터의 규격은 자동차용 창문 모터 이고, 모터가 시계 방향으로 돌아갑니다. 그리고 모터가 반시계 방향으로 돌아갑니다.

 이 버튼의 규격은 자동차용 창문 버튼 이고, up을 누려면 자동차 창문을 위로 올립니다. 그리고 down을 누르면 자동차 창문을 아래로 내립니다.

 버튼은 2 개 이고, 모터는  1 개 이다.

 이 버튼의 규격은 간이 엘리베이터용 버튼 이고, up을 누려면 간이 엘리베이터를 위로 올립니다. 그리고 down을 누르면 간이 엘리베이터를 아래로 내립니다.

 이 모터의 규격은 엘리베이터용 모터 이고, 모터가 시계 방향으로 돌아갑니다. 그리고 모터가 반시계 방향으로 돌아갑니다.

 버튼은 1 개 이고, 모터는  1 개 이다.
 */
반응형

'기초지식공부 > 디자인패턴' 카테고리의 다른 글

디자인 패턴이란?  (0) 2019.06.28