Here as much as I understand Operation takes in
extrinsicState as argument, but it will not use it at all, as far as it has
allState as member data.
I don't think that is the case.
allState is not a replacement for
extrinsicState. It is simply the unshareable state that is differentiated from the externally stored state.
In their example:
Glyph is the
FlyweightBase, and provides operations like
Character is the
intrinsicState is its character code,
allState holds a collection of
Glyphs (which can be
Characters. They aren't shared because the collections are each unique (though GOF says they could be later made to be shared).
extrinsicState is the
GlyphContext, which is the mapping between the glyphs and fonts, and since this state is external to the flyweights, it must be passed in to both concrete and unshared concerete flyweights.
The extrinsic state logically belongs in the flyweights, and has been extracted as an adornment. It must be passed to the concrete flyweight
Character so that state can be recovered, and it must be passed to unshared concrete flyweights (
Column), in part so that they can pass it to the
Characters in turn.
It is conceivable that
Columns could capture a reference to the extrinsic state (the
GlyphContext) and then they truly would not use their parameter. However, as they mention, with this design, clients don't have to know whether they are shareable or not. (This extra state would also be contrary to the flyweight design, as even the reference is not really necessary.)
Is it a good design? To take arguments you don't use, and if you will use, then you will have data duplication. This may even be Liskov Substitution Principle violation?
The flyweight pattern is an optimization, if you will, and, you can think of it is a refactoring of a simpler object-oriented design that is using too many objects.
The optimization works by separating intrinsic state from extrinsic state, with the assumption that the extrinsic state can be represented more efficiently than being replicated in each object, and, that now separated, the bulk of the remainder (the intrinsic state) can be shared and reused.
After the refactoring, you can now invoke all the same object-oriented methods that previously existed, but the cost is that you have to pass the extrinsic state as an additional parameter now.
As an optimization, if you don't absolutely need it you shouldn't use it just because you can. It makes the code harder to use, understand, maintain, etc..
But in computing, there are costs, and so when you need optimization, you need it!
Also note that you don't necessarily have to implement unshared concrete flyweight's, it's just that you can if you need it.