Модель — это чистые данные.
Это класс или структура, которые содержат только поля и свойства, без методов и логики.
Пример:
[Serializable]
public class UserProgress
{
public string UserId;
public string UserName;
public int Coins;
public int Crystals;
}
Прокси — это обертка над моделью, которая полностью повторяет её интерфейс.
Прокси используется для:
- Валидации данных перед их изменением.
- Подписки на изменения данных через события.
- Безопасного управления источником данных.
Пример:
public class UserProgressProxy
{
public event Action<int> OnCoinsChanged;
public UserProgress Origin { get; private set; }
public UserProgressProxy(UserProgress origin)
{
Origin = origin;
}
public int Coins
{
get => Origin.Coins;
set
{
Origin.Coins = value;
OnCoinsChanged?.Invoke(value);
}
}
}
Модуль разделяет данные (модели) и логику работы с данными (прокси).
Кроме того, он построен на принципах абстракции и расширяемости.
- Определяем данные, которые нужно сохранять (модели).
- Создаем прокси для работы с этими данными.
- Реализуем
IStorageService
— интерфейс для управления сохранением.
Интерфейс описывает базовые операции для работы с сохранениями:
SaveProgress()
— сохранить данные.LoadProgress()
— загрузить данные.DeleteAllProgress()
— удалить данные.
Пример интерфейса:
public interface IStorageService : IDisposable
{
public UserProgressProxy UserProgress { get; }
...
public void SaveProgress();
public void LoadProgress();
public void DeleteAllProgress();
}
Расширение интерфейса:
Если нужно добавить новый тип данных, достаточно:
- Создать новую модель.
- Написать для неё прокси (по желанию).
- Добавить её в
IStorageService
как новое свойство.
Класс для сохранения данных на Android и iOS.
Методы:
SaveProgress()
— сохраняет данные на диск в формате JSON.LoadProgress()
— загружает данные с диска и оборачивает их в прокси.DeleteAllProgress()
— удаляет файлы данных с диска.
Класс для интеграции с API Яндекс Игр (WebGL).
Методы:
SaveProgress()
— вызывает метод сохранения в плагине Яндекса.LoadProgress()
— не используется (данные загружаются автоматически через плагин).DeleteAllProgress()
— вызывает сброс прогресса через API плагина.
Модуль использует единый интерфейс для всех платформ.
Класс StaticProgressService
автоматически выбирает нужную реализацию (например, MobileGameStorageService
для Android) на основе текущей платформы.
Пример:
private static IStorageService CreateStorageService()
{
#if UNITY_WEBGL
return new YandexGameStorageService();
#elif UNITY_ANDROID
return new MobileGameStorageService();
#else
throw new System.NotSupportedException("Unsupported platform");
#endif
}
StaticProgressService.Instance.Load();
StaticProgressService.Instance.Save();
StaticProgressService.Instance.UserProgress.Coins += 100;
StaticProgressService.Instance.UserProgress.OnCoinsChanged += coins =>
{
Debug.Log($"Монеты изменились: {coins}");
};
-
Единый API
Не важно, где и как ты сохраняешь данные — структура интерфейса остаётся неизменной. -
Расширяемость
Легко добавить новый способ сохранения (например, удалённый сервер или SD-карту). -
Гибкость
Поддерживает как один класс для всех данных (GameData
), так и множество отдельных моделей. -
Лёгкость замены
Можно легко заменить способ сериализации (например, сJsonUtility
наNewtonsoft.Json
) в одном месте. -
Поддержка событий
Удобно отслеживать изменения данных через прокси.
Если ты используешь всего один класс данных (например, GameData
), то достаточно:
- Создать модель:
[Serializable]
public class GameData
{
public int Coins;
public string PlayerName;
}
- Добавить её в реализацию
IStorageService
:
public GameDataProxy GameData { get; private set; }
- Всё! Ты можешь использовать этот модуль даже с одним классом.