Search code examples
c++design-patternsmutableboost-optional

C++ design pattern for an item with multiple representations


I have an "item" whose data can be represented 3 ways. I can convert from one representation to any of the others, at a runtime cost. Once I do the conversion I'd like to keep the new representation around. Any representation of the data can be converted to any of the others without "modifying" the core data. Because of the runtime cost, I want a class that contains 3 representations of the data. At any time, 1 to 3 of them will be valid.

The real point of this is because it also has access methods, where the user can ask for something. This something can be gotten from 1 or possibly more of the representations. For example, you could get the "range" from representation1 and the "volume" from representations 2 or 3.

My solution was to create class with the 3 representations as member data (and a way to know if they are valid). Then I created a getRange() method that internally knows which representation it needs and creates that if necessary. This works fine and solves all my issues except that the get method cannot be const.

So the real issue with this solution is that even a "constant" instance of this class is not really const because it internally might create other representations. However it really is "constant" because changing representations does not modify the core data.

Is there a C++ design pattern that might help with this class? Any suggestions?


Solution

  • My solution was to create class with the 3 representations as member data (and a way to know if they are valid). Then I created a getRange() method that internally knows which representation it needs and creates that if necessary. This works fine and solves all my issues except that the get method cannot be const.

    This is the very purpose of the mutable type specified! In order to be able to update the internal representation while still having a const method, make the representation attributes mutable:

    struct A {
    
        int get_range() const {
            if (!_repr2.is_valid()) {
                _repr2 = Repr2(_repr1); // I am in a const method, but still
                                        // I can update a mutable attribute
            }
            return _repr2.get_range();
        }    
    
    private:
        mutable Repr1 _repr1;
        mutable Repr2 _repr2;
    };
    

    Here is a full example with two representations that uses std::unique_ptr to store the representation so you can easily check if one is instanciated or not.