首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我正确地使用了状态模式吗?

我正确地使用了状态模式吗?
EN

Stack Overflow用户
提问于 2018-11-28 22:30:25
回答 1查看 462关注 0票数 3

我正在学习我构建的示例项目中的状态模式(有限状态机),我知道更新UI的唯一方法是将呈现视图的引用传递给状态机,然后从我正在工作的状态更新UI。我做错了吗?

这是我的国家机器

代码语言:javascript
复制
class CapturePhotoStateMachine {
    var noPictureTakenState: NoPictureTakenState?
    var pictureTakenState: PictureTakenState?
    var initialState: InitialState?
    var vc: SignupAvatarView?

    var capturePhotoState: CapturePhotoState?

    init(viewController: SignupAvatarView) {
        noPictureTakenState = NoPictureTakenState(stateMachine: self)
        pictureTakenState = PictureTakenState(stateMachine: self)
        initialState = InitialState(stateMachine: self)
        vc = viewController
        capturePhotoState = initialState
    }

    func setCapturePhotoState(newState: CapturePhotoState) {
        self.capturePhotoState = newState
    }

    func takePicture() {
        self.capturePhotoState?.takePicture()
    }

    func savePicture(image: UIImage) {
        self.capturePhotoState?.savePicture(image: image)
    }


    func retakePicture() {
        self.capturePhotoState?.retakePicture()
    }

    func setup() {
        self.capturePhotoState?.setup()
    }
}

这是我的协议

代码语言:javascript
复制
protocol CapturePhotoState {
    func takePicture()
    func savePicture(image: UIImage)
    func retakePicture()
    func setup()
}

这是一个州的子类

代码语言:javascript
复制
class NoPictureTakenState: CapturePhotoState {

    var stateMachine: CapturePhotoStateMachine?

    init(stateMachine: CapturePhotoStateMachine) {
        self.stateMachine = stateMachine
    }

    func takePicture() {
        stateMachine!.vc?.previewView.isHidden = true
        stateMachine!.vc?.capturedImage.isHidden = false
        stateMachine!.vc?.saveButton.isHidden = false
        stateMachine!.vc?.retakePhoto.isHidden = false
        stateMachine?.setCapturePhotoState(newState: (stateMachine?.pictureTakenState)!)
    }

    func savePicture(image: UIImage) {
    }

    func retakePicture() {}

    func setup() {}
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-11-29 00:33:05

状态机的用途的关键似乎是,根据状态,您有要启用或禁用的接口对象。启用/禁用应该是视图控制器的工作。国家本身只是回答诸如“目前的情况是什么”和“下一步应该发生什么”等问题的基础。

下面是一个简单的简单状态机示例,说明了这一点。这是故意琐碎的。我们只有两个按钮,只有两个状态;在每个状态中,都应该启用一个按钮。状态是由枚举的情况表示的,当状态发生变化时,我们使用该枚举上的setter观察者来响应。枚举封装了有多少个状态以及下一个状态是什么的逻辑,而视图控制器则在状态更改和接口更改之间进行中介:

代码语言:javascript
复制
class ViewController: UIViewController {
    @IBOutlet weak var takePictureButton: UIButton!
    @IBOutlet weak var deletePictureButton: UIButton!
    @IBOutlet weak var pictureImageView: UIImageView! // not used in the example

    @IBAction func doTakePicture(_ sender: Any) {
        // do stuff
        doNextState()
    }

    @IBAction func doDeletePicture(_ sender: Any) {
        // do stuff
        doNextState()
    }

    enum State {
        case pictureNotTaken
        case pictureTaken
        var nextState : State {
            switch self {
            case .pictureNotTaken:
                return .pictureTaken
            case .pictureTaken:
                return .pictureNotTaken
            }
        }
    }
    var state : State = .pictureNotTaken {
        didSet {
            updateInterface()
        }
    }
    func doNextState() {
        self.state = self.state.nextState // triggers the setter observer
    }
    func updateInterface() {
        switch state {
        case .pictureNotTaken:
            takePictureButton.isEnabled = true
            deletePictureButton.isEnabled = false
        case .pictureTaken:
            takePictureButton.isEnabled = false
            deletePictureButton.isEnabled = true
        }
    }
}

也许你想要的是这种模式的一些扩展。

我发现更新UI的唯一方法是将呈现视图的引用传递给状态机。

这就是上面的模式所不能做的。策划人观察者为我们解决了这个问题。

现在,您可能会反对switch语句在updateInterface中做错了工作。它定位了接口如何在视图控制器中完全反映状态的知识。您的冲动是肯定地说,知识是状态的一部分(这就是为什么您以这样的方式构造代码)。

我的回答是:好的,是的,不是的。有时候,我确实有这种感觉,解决问题的方法是赋予状态机属性,表达视图控制器可能对当前状态对接口的含义产生的所有问题。这样,知识被移到状态,但是接口仍然被视图控制器正确地控制。

例如,我们可以将这两个属性添加到我们的状态枚举中:

代码语言:javascript
复制
enum State {
    // ... everything else is as before ...
    var userCanTakePicture : Bool { return self == .pictureNotTaken }
    var userCanDeletePicture : Bool { return self == .pictureTaken }
}

因此,现在,我们的updateInterface不需要任何关于每个状态意味着什么的特殊知识;它只需要询问接口应该是什么状态,这比较简单,并且可能会给出更令人满意的分权:

代码语言:javascript
复制
func updateInterface() {
    self.takePictureButton.isEnabled = state.userCanTakePicture
    self.deletePictureButton.isEnabled = state.userCanDeletePicture
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53529070

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档