Повышаю. Flyweight предоставляет спецификации публичного интерфейса для своихконфигурируемых аспектов.чтобы пользователь мог расширить библиотеку, реализовав собственные компоненты и предоставив их для инстанциаций шаблона класса<flyweight>.
В большинстве случаев существуют два типа сущностей, участвующих в расширении данного аспекта. Вес:
Сам компонент (император, шаблон фабричного класса).
,,,< [10] >,< [10] >,< [10] >,< [10] >.
Например, тип<static_holder>является спецификатором держателя, который используется<flyweight>для генерации фактических классов держателя, в этом случае инстанциации шаблона класса.<static_holder_class>. Обратите внимание, что<static_holder>является конкретным типом, а<static_holder_class>является шаблоном класса, поэтому спецификатор можно рассматривать как удобный способ обеспечить доступ к семейству связанных конкретных компонентов (различные возможные инстанциации шаблона класса):<flyweight>Внутренне выбирает конкретный компонент, соответствующий его внутренним потребностям.Сам компонент (например, шаблон фабричного класса).
Связанныйкомпонентный спецификатор, который является типом, представленным в качестве шаблонного аргументаflyweight.
For example, the type
static_holder
is a holder specifier which is used by flyweight to generate
actual holder classes, in this case instantiations of the class
template
static_holder_class.
Note that static_holder is a concrete type while
static_holder_class is a class template, so a specifier can be
seen as a convenient way to provide access to a family of related concrete
components (the different possible instantiations of the class template):
flyweight internally selects the particular component
appropriate for its internal needs.
[ORIG_END] -->
В некотором смысле, фабрики напоминают уникальные ассоциативные контейнеры, такие как<std::set>, хотя их ожидаемый интерфейс гораздо более лаконичен:
// example of a possible factory class templatetemplate<typenameEntry,typenameKey>classcustom_factory_class{public:typedef...handle_type;handle_typeinsert(constEntry&x);voiderase(handle_typeh);constEntry&entry(handle_typeh);};
Заводы параметризированы<Entry>и<Key>: Первый — это тип хранимых объектов, а второй — тип открытого ключа, на котором работает<flyweight>(например,<std::string>в<flyweight<std::string>>или<flyweight<key_value<std::string,texture> >>). Запись имеет общую ценность, с которой связаны объекты с весом, а также внутренняя бухгалтерская информация, но с точки зрения фабрики, однако, единственный факт, известный о<Entry>, заключается в том, что она неявно конвертируема в<const Key&>, и на основе их связанных<Key>, что записи должны считаться эквивалентными или нет. Функция члена фабрики<insert()>обнаруживает ранее сохраненную запись, связанная с ней<Key>эквивалентна записи проходящего объекта<Entry>(для некоторого отношения эквивалентности<Key>по отношению к фабрике), или сохраняет новую запись, если не найден эквивалент.<handle_type>к эквивалентной или вновь вставленной записи возвращается; это<handle_type>является токеном для дальнейшего доступа к записи через<erase()>и<entry()>. Обратитесь к ссылкедля официального определения концепции<Factory>.
Рассмотрим реальный пример реализации фабричного класса. Предположим, мы хотим отследить различные призывы Бооста. Функции «Flyweight of the<insert()>» и «<erase()>»: это можно сделать с помощью пользовательской фабрики, чьи методы «Flyweight» испускают микросообщения на консоль программы. Мы основываем реализацию функциональности репозитория на регулярной<std::set>:
<
template<typenameEntry,typenameKey>classverbose_factory_class{typedefstd::set<Entry,std::less<Key>>store_type;store_typestore;public:typedeftypenamestore_type::iteratorhandle_type;handle_typeinsert(constEntry&x){std::pair<handle_type,bool>p=store.insert(x);if(p.second){/* new entry */std::cout<<"new: "<<(constKey&)x<<std::endl;}else{/* existing entry */std::cout<<"hit: "<<(constKey&)x<<std::endl;}returnp.first;}voiderase(handle_typeh){std::cout<<"del: "<<(constKey&)*h<<std::endl;store.erase(h);}constEntry&entry(handle_typeh){return*h;}};
.Заметим, что фабрика параметризована поEntryиKey, так как эти типы обеспечиваются внутри Boost. Легкий вес, когда фабрика создается как часть механизмаflyeight; но ничто не мешает нам иметь больше шаблонных параметров для более точной конфигурации типа фабрики: например, мы могли бы расширитьverbose_factory_class, чтобы принять некоторый сравнительный предикат, а не по умолчаниюstd::less<Key>, или указать распределитель, используемый внутреннимstd::set.
Тот факт, чтоEntryконвертируется вconst Key&(что является единственным свойством, известным оEntry), используется в спецификацииstd::less<Key>в качестве сравнительного предиката дляstd::setEntrys, используемого в качестве внутреннего хранилища.
Как наша публикаhandle_typeмы просто используем итератор для внутреннейstd::set.
[ORIG_END] -->
Для того, чтобы подключить заказную фабрику к спецификации<flyweight>типа, нам нужна связанная конструкция, называемаязаводским спецификатором. Заводской спецификатор — это<Lambda
Expression>, принимающий два типа аргументов<Entry>и<Key>и возвращающий соответствующий заводской класс:
// Factory specifier (metafunction class version)structcustom_factory_specifier{template<typenameEntry,Key>structapply{typedefcustom_factory_class<Entry,Key>type;}};// Factory specifier (placeholder version)typedefcustom_factory_class<boost::mpl::_1,boost::mpl::_2>custom_factory_specifier;
Есть одна последняя деталь: чтобы реализовать<flyweight>интерфейс параметров шаблона свободного порядка, необходимо явно пометить заводской спецификатор как таковой, чтобы его можно было отличить от других типов спецификаторов. Повышаю. Flyweight предоставляет три различных механизма для выполнения этой маркировки:
Держатель — класс со статической функцией<get()>, дающий доступ к уникальному экземпляру данного типа<C>:
// example of a possible holder class templatetemplate<typenameC>classcustom_holder_class{public:staticC&get();};
<flyweight>Внутренне использует держателя для создания соответствующей фабрики, а также некоторых других глобальных данных. Спецификатор держателя - это<Lambda
Expression>, принимающий тип<C>, на котором работает соответствующий класс держателя:
// Holder specifier (metafunction class version)structcustom_holder_specifier{template<typenameC>structapply{typedefcustom_holder_class<C>type;}};// Holder specifier (placeholder version)typedefcustom_holder_class<boost::mpl::_1>custom_factory_specifier;
Как и в случае сзаводскими спецификаторами, спецификаторы держателей должны быть помечены, чтобы быть должным образом распознанными при предоставлении<flyweight>, и для этого существуют три доступных механизма:
// Alternatives for tagging a holder specifier#include<boost/flyweight/holder_tag.hpp>// 1: Have the specifier derive from holder_markerstructcustom_holder_specifier:holder_marker{...};// 2: Specialize the is_holder class templatenamespaceboost{namespaceflyweights{template<>structis_holder<custom_holder_specifier>:boost::mpl::true_{};}}// 3: use the holder<> wrapper when passing the specifier
// to flyweighttypedefflyweight<std::string,holder<custom_holder_specifier>>flyweight_string;
Пользовательская политика блокировки представляет следующий простой интерфейс:
// example of a custom policyclasscustom_locking{typedef...mutex_type;typedef...lock_type;};
где<lock_type>используется для приобретения/выпуска мутексов в соответствии сприложенной блокировкойидиомой:
mutex_typem;...{lock_typelk(m);// acquire the mutex
// zone of mutual exclusion, no other thread can acquire the mutex...}// m released at lk destruction
Формальные определения понятий<Mutex>и<Scoped Lock>приведены в ссылке. Чтобы принять политику блокировки в качестве шаблонного аргумента<flyweight>, класс должен быть соответствующим образом помечен:
// Alternatives for tagging a locking policy#include<boost/flyweight/locking_tag.hpp>// 1: Have the policy derive from locking_markerstructcustom_locking:locking_marker{...};// 2: Specialize the is_locking class templatenamespaceboost{namespaceflyweights{template<>structis_locking<custom_locking>:boost::mpl::true_{};}}// 3: use the locking<> wrapper when passing the policy
// to flyweighttypedefflyweight<std::string,locking<custom_locking>>flyweight_string;
Обратите внимание, что политика блокировки является собственным спецификатором, т.е. нет дополнительного класса, который может быть передан в качестве прокси для реального компонента, как в случае с заводами и владельцами.
Политики отслеживания вносят некоторую информацию о типе в процесс определения внутренней фабрики и предоставляют доступ к этой фабрике, чтобы обеспечить реализацию кода отслеживания. Политика отслеживания<Tracking>определяется как класс со следующими вложенными элементами:
Тип< [97] >.
Тип< [99] >.
Каждый из этих элементов опирается на предыдущий в том смысле, что он увеличивается. Внутреннее оборудование с массой тела направляет результаты, полученные элементом, в следующее:
Итак, чтобы определить фабрику некоторой инстанциации<fw_t><flyweight>,<Tracking::entry_type>вызывается с внутренним типом<Value>, неявно конвертируемым в<const fw_t::key_type&>, чтобы получить тип ввода для фабрики, который должен быть конвертируемым как в<const Value&>, так и в<const fw_t::key_type&>. Затем<Tracking::handle_type>подается внутренний тип ручки и помощник политики отслеживания для производства типа ручки завода. Наблюдательный читатель, возможно, обнаружил кажущуюся замкнутость:<Tracking::handle_type>производит тип ручки фабрики, и в то же время передается помощник отслеживания, который предоставляет доступ к фабрике. Решение этой загадки происходит от осознания того факта, что<TrackingHandler>являетсянеполным типомк моменту его передачи<Tracking::handle_type>: Только когда<Handle>будет инстанцирован на более позднем этапе, этот тип будет завершен.ТипTracking::entry_type.
ТипTracking::handle_type.
Each of these elements build on the preceding one, in the sense that
Boost.Flyweight internal machinery funnels the results produced by an
element into the following:
Tracking::entry_typeявляется.Lambda
Expression, принимая два различных типа, названныхValueиKeyтак, чтоValueнеявно конвертируется вconst Key&. Предполагается, что выражение возвращает тип, неявно конвертируемый как вconst Value&, так и вconst Key&.Tracking::entry_typeсоответствует фактическому типу записей, хранящихся на фабрике,: позволяя политике отслеживания принимать участие в определении этого типа, политика может добавлять внутреннюю информацию отслеживания к данным ввода в случае необходимости. Если дополнительная информация не требуется, политика отслеживания может просто вернутьсяValueв видеTracking::entry_type.
БинарныйLambda
ExpressionTracking::handle_typeвызывается с типамиInternalHandleиTrackingHandlerдля получения типаHandle, который будет использоваться в качестве типа ручки на фабрике.TrackingHandlerпередается в качестве аргумента шаблонаTracking::handle_type, чтобы предложить функциональность, поддерживающую реализацию кода отслеживания.
So, in order to define the factory of some instantiation
fw_t of flyweight, Tracking::entry_type
is invoked with an internal type Value implicitly convertible
to const fw_t::key_type& to obtain the entry type for the factory,
which must be convertible to both const Value& and
const fw_t::key_type&.
Then, Tracking::handle_type is fed an internal handle
type and a tracking policy helper to produce the factory handle type.
The observant reader might have detected an apparent circularity:
Tracking::handle_type produces the handle type of
the flyweight factory, and at the same time is passed a tracking helper
that grants access to the factory being defined!
The solution to this riddle comes from the realization of the fact that
TrackingHandler is an incomplete
type by the time it is passed to Tracking::handle_type:
only when Handle is instantiated at a later stage will this
type be complete.
[ORIG_END] -->
Для того, чтобы политика отслеживания была передана<flyweight>, она должна быть помечена так же, как и остальные спецификаторы.
// Alternatives for tagging a tracking policy#include<boost/flyweight/tracking_tag.hpp>// 1: Have the policy derive from tracking_markerstructcustom_tracking:tracking_marker{...};// 2: Specialize the is_tracking class templatenamespaceboost{namespaceflyweights{template<>structis_tracking<custom_tracking>:boost::mpl::true_{};}}// 3: use the tracking<> wrapper when passing the policy
// to flyweighttypedefflyweight<std::string,tracking<custom_tracking>>flyweight_string;
Политики отслеживания являются их собственными спецификаторами, то есть они предоставляются непосредственно в качестве аргументов шаблона для шаблона класса<flyweight>.
Статья Boost.Flyweight Documentation - Tutorial - Extending Boost.Flyweight раздела Boost.Flyweight Documentation - Tutorial может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.