Визуальное программирование и MFC

       

Создание нескольких объектов одного класса: фабрики классов


Если клиенту нужен только один объект, то проще всего создать его с помощью CoCreateInstance. И все же случается, что клиенту может понадобиться много экземпляров объектов одного и того же класса. Чтобы их создание выполнялось эффективно, клиент может получить доступ к фабрике класса (class factory) — объекту, способному создавать другие объекты. Каждая фабрика класса знает, как создавать объекты одного конкретного класса (хотя название "class factory" не вполне удачно — ведь эти фабрики создают экземпляры классов, а не классы). Фабрики классов — полноценные объекты СОМ: доступ к ним осуществляется через интерфейсы, они поддерживают IUnknown и т.д. И все же они необычные объекты, так как могут создавать другие объекты СОМ.

Дело в том, что все объекты, с которыми мы встречались до сих пор, созданы фабрикой класса. Даже когда клиент просто вызывает CoCreateInstance, реализация этой функции в библиотеке СОМ создает объект с помощью фабрики класса. CoCreateInstance скрывает эти детали от клиента. Но на самом деле она использует методы интерфейса IClassFactory, описываемые ниже.

Интерфейс IClassFactory

Чтобы называться фабрикой класса, объект должен поддерживать интерфейс IClassFactory. Этот замечательно простой интерфейс содержит только 2 метода:

  • CoCreateInstance создает новый экземпляр класса, объекты которого может создавать данная фабрика. Клиент не передает этому методу в качестве параметра CLSID, так как класс объекта неявно определяется самой фабрикой. И все же клиент задает IID, чтобы получить указатель на нужный ему интерфейс. (Реализация этого метода фабрикой класса, написанной на C++, может создавать новый объект с помощью оператора C++ new.)
  • LockServer позволяет клиенту сохранить сервер загруженным в память. Объект-фабрика, как и другие объекты, поддерживает собственный счетчик ссылок, для учета количества использующих его клиентов. Однако по разным (очень сложным) соображениям этого счетчика недостаточно, чтобы удерживать сервер загруженным в память.
    Чтобы сервер гарантированно продолжал работать, можно использовать IClassFactory::LockServer.


  • В некоторых случаях интерфейс IClassFactory слишком прост. На сегодня имеется новый интерфейс IClassFactory2, добавляющий новые возможности. Так как IClassFactory2 наследует от IClassFactory, в его состав входят методы Createlnstance и LockServer, Однако он поддерживает и еще несколько методов, связанных с лицензированием. Используя эти методы, можно разрешить создание новых объектов только лицензированным клиентам — таким, на чьих компьютерах установлена легальная, предположительно оплаченная копия программного обеспечение. Так как данная возможность особенно полезна для управляющих элементов ActiveX.



    Использование фабрики класса



    Чтобы получить доступ к фабрике класса, клиент вызывает функцию библиотеки СОМ CoGetClassObject. Этой функции передается CLSID класса объектов, которые будут создавать фабрики, а не CLSID самой фабрики. Клиент задает также IID интерфейса, нужного ему для работы с фабрикой. Конечно, обычно это IID интерфейса IClassFactory. Кроме того, как и в случае с CoCreateInstance, клиент может также задать тип сервера, который должен быть запущен для фабрики и ее объектов. Если для фабрики запрашивается, например, сервер "в процессе", то и объекты, созданные фабрикой, тоже будут выполняться данным сервером "в процессе".

    Продемонстрируем использование фабрики класса. Допустим, клиент уже вызвал CoGetClassObject, библиотека СОМ запустила фабрику класса и возвратила указатель на интерфейс IClassFactory этой фабрики. Получив указатель, клиент вызывает метод IClassFactory::Createlnstance данного интерфейса (шаг 1). Среди параметров этого вызова клиент передает IID интерфейса, указатель на который ему необходим. В ответ фабрика класса создает объект (шаг 2) и возвращает клиенту указатель на заданный интерфейс (шаг 3). Теперь клиент может использовать возвращенный ему указатель для вызовов методов интерфейса (шаг 4).


    Содержание раздела