Приведенный в листинге 8.1 пример кода иллюстрирует два способа отложенного создания и кэширования глобально используемых графических ресурсов. Существует два способа создания объектов:
1. Пакетное создание групповых ресурсов. Приведенный ниже код создает списочный массив, содержащий четыре растровых изображения. Эти изображения являются кадрами анимации, поэтому они загружаются все вместе и помещаются в индексированный массив, откуда их можно легко извлекать. Программный код, которому требуется доступ к этой коллекции изображений, должен использовать вызов GraphicsGlobals.PlayerBitmapsCollection;. Если массив изображений уже загружен в память, функция незамедлительно
возвращает кэшированный объект. В противном случае отдельные ресурсы изображений сначала загружаются в массив и лишь затем возвращаются. Если приложение переходит в состояние, в котором пребывание изображений в памяти не требуются, код приложения может выполнить вызов GraphicsGlobals.g_PlayerBitmapsCollection_CleanUp;, в результате чего произойдет освобождение растровых ресурсов и массива. Системные ресурсы, задействованные для обслуживания растровых изображений, будут немедленно освобождены, а управляемая память, которую занимали эти объекты, будет соответствующим образом восстановлена в процессе сборки мусора.
2. Индивидуальное создание графических ресурсов. В случае ресурсов, которые не должны обязательно использоваться вместе, как в приведенном выше примере, часто оказывается удобным создать функцию кэшированного доступа, посредством которой и реализуется управление доступом к ресурсу. Когда происходит первое обращение к этой функции с запросом ресурса (например, GraphicsGlobals.g_GetBlackPen;), она создает его экземпляр. В случае часто используемых ресурсов такой подход оказывается намного более эффективным, чем постоянное создание и уничтожение экземпляров ресурса всякий раз, когда он требуется для выполнения того или иного фрагмента кода. Создавая приведенный ниже код, я допустил, что все ресурсы должны освобождаться одновременно, и написал функцию (GraphicsGlobals.g_CleanUpDrawingResources;), которая освобождает все кэшированные ресурсы, которые были созданы. Эта функция должна вызываться тогда, когда приложение переходит в состояние, в котором эти ресурсы не требуются.
Используя кэширование, руководствуйтесь здравым смыслом
Если предполагается многократное использование одних и тех же ресурсов внутри функции, то вызов функции (или свойства) кэшированного доступа всякий раз, когда требуется данный ресурс, является неэффективным. В подобных случаях лучше вызвать эту функцию один раз и хранить ресурс в локальной переменной в течение всего времени, пока в данном ресурсе будет существовать необходимость. Тем самым вы получаете выигрыш от того, что используете глобально кэшированный ресурс, а не создаете и уничтожаете ресурс внутри функции, и повышаете эффективность вычислений, поскольку избавляетесь от лишних вызовов функции в своем алгоритме. Здравый смысл подскажет вам, когда такой подход является оправданным.
Листинг 8.1. Применение отложенной загрузки, кэширования и освобождения графических ресурсов