Swift Optionals最佳做法 [英] Swift Optionals best practices

查看:81
本文介绍了Swift Optionals最佳做法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想我理解Swift可选属性的思想,即具有非可选类型的属性表示必须,而具有可选类型的属性则表示MAY HAVE,但在我看来,它是其中的一种功能,例如强制性异常处理或强制性缩进,尽管从理论上讲会带来一些意想不到的实际后果。这就是我面临的情况。我正在创建一个医疗应用程序以评估认知能力。该测试是由提供者进行的,它由10种不同的活动组成。应用程序的数据模型是一个简单的类 Test ,用于收集活动的结果。每个活动都有自己的类别,患者和提供者也是如此。业务逻辑规则规定必须完成所有活动或测试无效,并且患者和提供者显然是强制性的。类 Test 的自然定义为

I think I understand the idea behind Swift optionals, i.e. a property with a non optional type represents a MUST HAVE while a property with an optional type is a MAY HAVE, but it seems to me that it's one of those features, like mandatory exception handling or mandatory indentation, that while great in theory have some unintended practical consequences. This the situation I'm facing. I'm creating a medical application to assess cognitive abilities. The test is administered to a patient by a provider and it consists of, let's say, 10 different activities. The data model of the application is a simple class Test that collects the results of the activities. Each activity has its own class, so do the patient and the provider. The business logic rules that all the activities must be completed or the test is invalid, and the patient and the provider are obviously mandatory. The natural definition for the class Test would be

 class Test {
    var provider: Provider
    var patient: Patient
    var activity1: Activity1
    var activity2: Activity2
    ...
    var activity10: Activity10
    }

现在的问题是,创建类 Test的实例,我需要所有活动的所有结果;在实践中,我必须保留 Provider Patient 和活动的所有个体实例,并且仅在完成测试创建 Test 的实例,这当然是不切实际的。因此,出于实际目的, Test 的所有属性都可以设置为可选,并且该类将以增量方式填充,但是现在类 Test 不能忠实地代表数据模型;此外,必须解开对属性的任何访问。一种选择是创建一系列非可选的活动,这些活动可以逐渐增长,但是该类又一次不能代表数据模型的意图。最后,可以创建具有所有可选属性的姐妹类 PartialTest ,并在完全填充 PartialTest 时创建 Test 的实例。仍然看起来太过分了。

Now the problem is that to create an instance of class Test, I need to have all the results for all the activities; in practice I have to carry over all the individual instances of Provider, Patient and the activities and only at the completion of the test create the instance of Test, this is of course impractical. So, for practical purposes, all the properties of Test can be made optional and the class is populated incrementally, but now the class Test doesn't represent the data model faithfully; moreover, any access to the properties must be unwrapped. One option would be to create a non-optional array of activities that can grow incrementally, but once again the class wouldn't represent the intentions of the data model. Finally, one can create a "sister class" PartialTest, with all optional properties, and when PartialTest is fully populated create an instance of Test. Still it seems an overkill.

那么,我是否误解了Swift中可选对象的作用?如果没有,是否有任何实际方法可以使类 Test 保持应有的状态?

So, am I misinterpreting the role of optionals in Swift? If not, is there any practical way to keep the class Test as it should be?

推荐答案

您可以执行以下操作:

class Test {
    var provider: Provider
    var patient: Patient
    var activity1: Activity1! = nil
    var activity2: Activity2! = nil
    // ...
    var activity10: Activity10! = nil

    var isComplete: Bool {
        return activity1 != nil
            && activity2 != nil
            // ...
            && activity10 != nil
    }
}

...然后只能访问在测试中具有 isComplete == true 的活动时,我认为可以从概念上改进设计。

... and then only access activities in the test when it has isComplete == true, I think the design can be conceptually improved.

通常,我会重新考虑设计,以摆脱束缚自己在Test类中进行的一系列活动的约束。例如:

But generally I would reconsider design to get away from restraining myself with a hardcoded set of activities in the Test class. E.g.:

protocol Activity {
    var isMandatory: Bool { get }
    var isComplete: Bool { get }
}

struct Activity1: Activity {
    let isMandatory: Bool

    var result1: Int! = nil

    var isComplete: Bool {
        return result1 != nil
    }

    init(isMandatory: Bool) {
        self.isMandatory = isMandatory
    }
}

class Test {
    var provider: Provider
    var patient: Patient
    var activities: [Activity] = [
        Activity1(isMandatory: true)
        // ...
    ]

    var isComplete: Bool {
        return activities.reduce(true) {
            $0 && $1.isComplete
        }
    }
}

...或某种更好的方法。

... or some sort of even better approach.

这篇关于Swift Optionals最佳做法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆