【입문】iOS 앱 개발 #4【아키텍처의 설계】

아키텍처 설계



이번에는 팩맨 게임을 구축할 때 전체 아키텍처를 설계한다.

사양서로부터 화면 모드는 4개 있어, 각각의 모드 내에는 캐릭터가 있어 이동 처리 등이 있다. 이들은 하나의 객체로 관리되고 처리됩니다.



설계 정책



각 화면 모드를 객체로 취급하고 쉽게 전환 조작하고 싶습니다.
attractMode.startSequence()
// ・・・アトラクトモード実行中・・・

// アトラクトモードからクレジットモードへ切り替える
attractMode.stopSequence()
creditMode.startSequence()
// ・・・クレジットモード実行中・・・

이런 느낌.

또한 이벤트 메시지를 화면 모드의 객체에 쉽게 알리고 싶습니다.
attractMode.sendEvent(message: .Update, parameter: [16])
attractMode.sendEvent(message: .Touch, parameter: [x,y])

이벤트 메시지는 표시 갱신 타이밍(Update)이나 터치 이벤트 등으로, 화면 모드가 무효인 것에는 통지하지 않게 한다.

요약하면 다음과 같은 객체의 계층 구조를 만들 수 있습니다.



이러한 기본 컴퍼넌트의 클래스를 작성한다.

CbObject class(기본 클래스)


/// Based object class
class CbObject {

    /// Kind of Message ID to handled events in object.
    enum EnMessage: Int {
        case None
        case Update
        case Timer
        case Touch
        case Swipe
        case Accel
    }

    /// When it is true, object can handle events.
    var enabled: Bool = true

    /// For accessing parent objects.
    private var parent: CbObject?

    /// Initialize self without parent object
    init() {
        parent = nil
    }

    /// Initialize self with parent object
    /// - Parameter object: Parent object
    init(binding object: CbObject) {
        parent = object
        parent?.bind(self)
    }

    /// Bind self to a specified object
    /// - Parameter object: Object to bind self.
    func bind( _ object: CbObject) {
        // TO DO: override
        // (This is pure virtual method.)
    }

    // Send event messages
    /// - Parameters:
    ///   - id: Message ID
    ///   - values: Parameters of message.
    func sendEvent(message id: EnMessage, parameter values: [Int]) {
        receiveEvent(sender: self, message: id, parameter: values)
    }

    /// Handler called by sendEvent method to receive events
    /// - Parameters:
    ///   - sender: Message sender
    ///   - id: Message ID
    ///   - values: Parameters of message
    func receiveEvent(sender: CbObject, message: EnMessage, parameter values: [Int]) {
        guard enabled else { return }
        if message == .Update {
            update(interval: values[0])
        } else {
            handleEvent(sender: sender, message: message, parameter: values)
        }
    }

    /// Event handler
    /// - Parameters:
    ///   - sender: Message sender
    ///   - id: Message ID
    ///   - values: Parameters of message
    func handleEvent(sender: CbObject, message: EnMessage, parameter values: [Int]) {
        // TO DO: override
        // (This is pure virtual method.)
    }

    /// Update handler
    /// - Parameter interval: Interval time(ms) to update.
    func update(interval: Int) {
        // TO DO: override
        // (This is pure virtual method.)
    }

}

기저 클래스의 CbObject 는, init 로 상위의 오브젝트와의 관련지를 실시할 수 있다. sendEvent 메소드로 메세지를 송신할 수 있어 메세지가, .Update 라면, update 핸들러가 불려, 그 이외는, handleEvent 가 불린다. 핸들러는 파생 클래스에서 재정의하여 처리합니다. 프로퍼티의 enabled 를 false 로 하면(자), 핸들러는 불리지 않게 된다.

CbContainer class (파생 컨테이너 클래스)


/// Container class that bind objects.
class CbContainer : CbObject {

    private var objects: [CbObject] = []

    /// Bind self to a specified object
    /// - Parameter object: Object to bind self.
    override func bind( _ object: CbObject) {
        objects.append(object)
    }

    /// Handler called by sendEvent method to receive events
    /// It sends messages to all contained object.
    /// - Parameters:
    ///   - sender: Message sender
    ///   - id: Message ID
    ///   - values: Parameters of message
    override func receiveEvent(sender: CbObject, message: EnMessage, parameter values: [Int]) {
        guard enabled else { return }

        super.receiveEvent(sender: sender, message: message, parameter: values)

        for t in objects {
            t.receiveEvent(sender: self, message: message, parameter: values)
        }
    }
}

파생 컨테이너 클래스의 CbContainer는 sendEvent 메서드에서받은 메시지를 연관된 모든 개체로 보냅니다. 마찬가지로 속성의 enabled를 false로 설정하면 이벤트 처리기가 더 이상 호출되지 않습니다.

사용방법


class MyObject: CbObject {
    override func update(interval: Int) {
        print("Update!")
    }
}

func test() {
    root  = CbContainer()
    node1 = CbContainer(binding: root)
    node2 = MyObject(binding: node1)

    root.sendEvent(message: .Update, parameter: [16])
}

root 에 보낸 메시지가 말단의 node2 의 객체에 도착하게 된다.

요약



전체 개체의 관리, 이벤트 메시지의 구조를 설계했다.

고도 100행 정도의 코드이지만, 처음에 이것들을 결정해 두지 않으면, 나중에, 고생할 것 같은 생각이 든다.

다음은 CbContainer 클래스를 상속하여 화면 모드 클래스를 작성한다.

다음글



【입문】iOS 앱 개발 #5 【시퀀스의 설계】

좋은 웹페이지 즐겨찾기