Я бы не рекомендовал ни один из этих двух шаблонов.
В модели человека не должно быть никаких ссылок на представления (то есть не должно быть ссылок на UIKit). Вы не хотите объединять ваш вид (такие вещи, как кнопки, изображения, chrome и т. Д. 1027 *., Которые вы видите на экране) и модели (абстрактное представление всей доски, представляющее, какие квадраты имеют бомбы, а какие не и какие квадраты все еще скрыты, а какие не были скрыты).
FWIW, я также лично был бы склонен оставить bombCountAround
свойство, которое вычисляется Board
для данной строки и столбца. На самом деле это не свойство какого-либо конкретного квадрата, а скорее связь между различными квадратами. Теоретически у вас может быть свойство захватывать это, чтобы избежать необходимости пересчитывать его на лету, но вычислительные затраты на просмотр восьми окружающих ячеек настолько минимальны, что это действительно не нужно.
Например, у меня может быть объект для определенного квадрата на доске:
struct Square {
var isBomb: Bool
var isHidden: Bool
var hasUserFlagged: Bool
}
Эта модель представляет все, что нам нужно знать о ячейке, когда мы приступаем к созданию представлений. В частности, действительно ли квадрат является бомбой или нет, квадрат все еще скрыт (например, пользователь вообще не нажимал на него), или пользователь установил там флаг, чтобы показать, что он думает, что там есть бомба или нет .
Кстати, обратите внимание, что я не использую Cell
где-либо в названии модели, так как это часто обозначает объект UIKit, например, ячейку представления коллекции. Модель не должна беспокоиться о реализации представления (т. Е. Используете ли вы ячейки представления коллекции, или просто кнопки в представлениях стека, или просто представления изображения с ограничениями). И Cell
подразумевает тип визуального элемента, а не абстрактный квадрат на доске.
С учетом сказанного, мы, вероятно, хотим, чтобы структура представляла всю доску всех этих квадратов, может быть Board
это представляет всю игровую доску:
struct Board {
private var squares: [[Square]]
init(width: Int, height: Int, bombCount: Int) {
// build the squares array of array of `Square`, setting a certain number to have bombs
}
}
extension Board {
func isBomb(column: Int, row: Int) -> Bool {
// look up to see if the `Square` at that row and column is a bomb or not
}
func howManyBombsNear(column: Int, row: Int) -> Int {
// calculate how many nearby bombs there are
}
}
Теперь, это может быть не той моделью. Возможно, вы захотите отделить первоначальную настройку того, где находятся бомбы, от статистики времени игры о том, что было скрыто пользователем, и что имеет флаги. Это зависит от вас.
Но сообщение о том, что модель должна быть полностью свободна от любых типов, связанных с представлением. Представление полностью абстрагировано от модели, так что вы можете реализовать его так, как вам нужно для рассматриваемой платформы (например, ваша цель не-Catalyst macOS может использовать совершенно другой набор представлений, чем ваши цели iOS / iPadOS / tvOS).