【发布时间】:2017-03-30 21:46:40
【问题描述】:
假设我有一家面包店和一份原料清单:
enum Ingredient {
case flower = 1
case sugar = 2
case yeast = 3
case eggs = 4
case milk = 5
case almonds = 6
case chocolate = 7
case salt = 8
}
一个案例的rawValue代表库存编号。
然后我有两个食谱:
巧克力蛋糕:
- 500g花
- 300克糖
- 3 个鸡蛋
- 200毫升牛奶
- 200克巧克力
杏仁蛋糕:
- 300克花
- 200克糖
- 20g酵母
- 200克杏仁
- 5 个鸡蛋
- 2g 盐
现在我定义一个函数
func bake(with ingredients: [Ingredient]) -> Cake
我当然信任我的员工,但我仍然想确保他们只使用正确的原料来烘烤蛋糕。 ????
我可以通过像这样定义两个单独的枚举来做到这一点:
enum ChocolateCakeIngredient {
case flower
case sugar
case eggs
case milk
case chocolate
}
enum AlmondCakeIngredient {
case flower
case sugar
case yeast
case eggs
case almonds
case salt
}
然后像这样烤蛋糕:
// in chocolate cake class / struct:
func bake(with ingredients: [ChocolateCakeIngredient]) -> ChocolateCake
// in almond cake class / struct:
func bake(with ingredients: [AlmondCakeIngredient]) -> AlmondCake
但是我不得不一遍又一遍地重新定义相同的成分,因为两种蛋糕都使用了许多成分。我真的不想那样做——尤其是在枚举案例中附加了库存编号为rawValues。
这让我想到了一个问题,在 Swift 中是否有办法将一个枚举限制为另一个枚举的某些情况?类似(伪代码):
enum ChocolateCakeIngredient: Ingredient {
allowedCases:
case flower
case sugar
case eggs
case milk
case chocolate
}
enum AlmondCakeIngredient: Ingredient {
allowedCases:
case flower
case sugar
case yeast
case eggs
case almonds
case salt
}
这样的组合可能吗?我该怎么做?
或者我可以在这种情况下使用另一种模式?
更新
从这个问题的所有 cmets 和答案中,我认为我为这个问题选择的示例有点不合适,因为它没有归结问题的本质,并且在类型安全方面留下了漏洞。
由于此页面上的所有帖子都与此特定示例相关,因此我在 Stackoverflow 上创建了一个新问题,其中包含一个更易于理解且一针见血的示例:
➡️Same question with a more specific example
【问题讨论】:
-
在 Java 中,这在编译时更难实现,而在运行时更容易实现。您的员工会自己编写代码吗?如果不是,则没有强制要求为您的子类型提供严格的类型安全。在运行时对代码中的集合进行错误检查会更简单。
-
您似乎正试图将约束放在枚举中,而不是将它们保留在它们所属的位置 - 使用枚举的类型。这看起来不像是可扩展的架构。
-
您可以通过将每个
case设为结构然后将协议AlmondCakeIngredient添加到可用于制作杏仁蛋糕的每种成分来做到这一点,但您会遇到其他可扩展性问题。 -
另外,添加新成分需要重新编译代码。例如,为什么不将成分作为数据保存在外部文件中?
-
@scottb:我的“员工”只是留在面包店样本域中的一个隐喻。我现实我将编写代码或我的一些队友。这只是说“我想要类型安全(在编译时)”。 ;) 你是对的:在运行时进行检查似乎很多更容易,不仅在 Java 中,在 Swift 中也是如此。
标签: swift enums restriction