SwiftUI MVVM记忆卡游戏emoji数组为何放在ViewModel而非Model
MVVM架构下emoji数组放在ViewModel层的合理性说明
这个设计完全符合MVVM分层规范,你产生疑惑的核心原因是没有划清通用核心业务数据和具体场景配置数据的归属边界:
- 你现在实现的
MemoryGameModel是高度泛化的通用组件:通过泛型CardContent承载卡牌内容,根本不关心卡牌上显示的是emoji、文字、图片还是其他元素,它只负责实现记忆卡牌游戏的核心规则——成对生成卡牌、翻牌交互、匹配判定这类和展示内容无关的底层逻辑。要是把固定的emoji数组写死在Model里,这个Model就只能做emoji主题的记忆卡牌,后续要做数字记忆卡、成语记忆卡、图片记忆卡的时候,就得直接改Model层代码,完全违背了单一职责、低耦合高内聚的设计原则。 - 放在ViewModel里的emoji数组,本质是「当前emoji主题记忆游戏的场景配置」。ViewModel本来就是Model和View之间的适配层:你现在要做emoji版本的游戏,ViewModel就负责选emoji作为卡牌内容,通过Model初始化传入的内容生成闭包,把配置注入到通用Model实例里;后续要是想做其他主题的记忆游戏,只需要新建对应的ViewModel、传入不同的内容数组就行,核心Model层的代码一行都不用改,复用性极强。
- 给你个非常好记的判断标准:如果改了某份数据,游戏的核心运行规则会变,那它就该放Model层——比如你现在写在Model里的卡牌翻开状态、匹配状态、选卡逻辑都属于这类;如果改了某份数据,核心玩法逻辑一点没变,只是展示的内容主题换了,那它就是场景配置,应该由ViewModel提供。
对应实现代码
ViewModel层代码
import SwiftUI class EmojiMemoryGame // 这是ViewModel { static let emojis = ["floaf","taco","george","chicken","squeaky","cat","dollar","a","b","c","d","e","f","g","h"] // 示例用文字替代emoji static func createMemoryGame() -> MemoryGame<String> { MemoryGame<String>(numbersOfPairsOfCards: 4) { pairIndex in emojis[pairIndex]} } private var model : MemoryGame<String> = createMemoryGame() var cards: Array<MemoryGame<String>.Card> { model.cards } }
Model层代码
import Foundation struct MemoryGame<CardContent> // 这是MVVM中的Model层 { private(set) var cards : Array<Card> func choose(_ card: Card) { } init(numbersOfPairsOfCards: Int, createCardContent: (Int) -> CardContent) { cards = Array<Card>() // 向卡牌数组中添加 numbersOfPairsOfCards*2 张卡牌 for pairIndex in 0..<numbersOfPairsOfCards { let content = createCardContent(pairIndex) cards.append(Card(content: content)) cards.append(Card(content: content)) } } struct Card { var isFaceUp: Bool = false var isMatched: Bool = false var content: CardContent } }
小提示:现在ViewModel里的
emojis用了static静态属性,后续如果要做多主题切换功能,改成实例属性绑定不同主题配置会更灵活。
内容的提问来源于stack exchange,提问作者Tom S
相关产品推荐
相关产品推荐

