
Michael Marcin wrote:
The name factory for what is currently in place is misleading. Isn't it really just an associative container?
The name factory is only used to refer to the internal mechanism Boost.Flyweight uses to store all elements. Boost.Flyweight is neither a factory nor a a container, it is a smart reference (in lack of a better name). flyweight<T> aims at being the same at T, except it will use sharing behind the scenes to reduce memory usage (each flyweight<T> is actually a reference to some T stored in a flyweight factory shared between all instances). Also, you're saying it's not a factory but really an associative container, while a factory is defined as being an associative container in Boost.Flyweight.
I'm trying to use flyweight to represent texture objects right now. These are surely a good candidate for use with flyweight as they are one of the examples given.
And the example really tells everything about how it should be done.
My textures are fairly simple objects, with low coupling. Creating a texture is however expensive and has a lot of dependencies (libjpeg,libpng,etc). I typically have a TextureFactory which decouples the construction of a texture from the actual texture object and allows the work required to setup the various libraries to read images to be reused by all textures constructed from the same TextureFactory instance.
It doesn't seem possible to have this decoupling with flyweight. Am I missing something?
The thing is you're not create a factory or perform decoupling at all. The goal of boost::flyweight is to do that for you. So you just write struct texture { texture(const std::string& name) { /* load up my texture */ } ... }; And then you have a texture, which can be constructed independently of any other instance without any factory or anything, which doesn't share state with anyone etc. Basically, a fairly normal value type with eager evaluation, with the advantages and disadvantages it means. And that's when flyweight kicks in. It will turn any type into a memoized one, using a global table behind the scenes. Boost.Flyweight does this by taking an object of such a type, seeing if it is in a global table, and behaving as a reference to that object in the table. If the object is not in the table, it is added. The problem, however, is that this approach requires the object to be constructed *before* the look-up, which is potentially useless if it's already in the table. The basic idea is then to be able to provide the constructor arguments instead of the object itself, and use those arguments as key for the look-up or for creating the object if needed. That is what Boost.Flyweight does under the key_value name. flyweight<T> could be implemented in terms of flyweight<key_value<T, T, self_extractor> >. If there is some specific thing you want to customize, changing the factory, holder, locking ou tracking policy to custom ones is also possible. The factory defines the associative container being used. The holder defines how the factory is stored. Locking policy and tracking policies seem self-explanatory. You can even do garbage collection by using no tracking and doing the work in the factory. May not be a very elegant design however.