How do I change an immutable object?

Sorry I couldn't come up with a good title for this question ...

When I start the application, I load objects from the database through the DB access library by calling their class CDbObject

.

class CDbObject
{
   //...
   virtual CState getState() const { return m_state; }

protected:
    CState m_state;
}

      

At runtime, I get messages corresponding to the state changes in these database objects.
I want to minimize DB access and thus not reload the full object when its state has changed.
Instead, I want to wrap DB objects and make them modifiable somehow. I can't just get a class, implement a method setState()

and create objects of this class, because I need to use the objects that the DB access library provides me. Objects don't have a copy mechanism, and I don't want to touch this code at all if possible.

I could create a wrapper class that stores a pointer to a CDbObject instance and looks like this:

class CWrapper
{
public:
    CWrapper(CDbObject* p): m_pDbObject(p)
    {
        m_state.setValid(false);
    }

    void setState(CState state)
    {
        m_state.copy(state);
        m_state.setValid(true);
    }

    CState getState() const
    {
        return m_state.isValid() ? m_state : m_pDbObject->getState();
    }

private:
    CDbObject* m_pDbObject;
    CState m_state;
}

      

But the obvious downside is that I will have to duplicate the complete interface of the wrapped class.
To avoid duplication of the interface, I could provide access to the wrapped object, but that makes the wrapping almost useless because the user could get the wrong state if they aren't careful enough.

Is there an elegant way to achieve what I want?

Edit:

In short: I want to make it transparent to the user where the status of the object is stored. The user should get the current status by calling one method. Hope this improves a little.

+2


source to share


3 answers


I'm with Jason, a class derived from CDbObject fixes the problem quite easily if those objects don't appear from some opaque interface.



However, if your application crashes and this status is not written back to the db, what kind of havoc is it causing? How many times a db exists for persistence, if you remove / hide that persistence, can you gracefully restore?

+1


source


You may find operator-> useful. Depending on what you want the behavior to run when you call a function in an invalid state, add this function to the CWrapper:

CDbObject* operator->()
{
  return m_state.isValid() ? m_pDbObject : NULL;
}

      

or that:



CDbObject* operator->()
{
  if (!m_state.isValid())
    m_pDbObject.update();
  return m_pDbObject;
}

      

Then use the wrapper type as auto_ptr:

CWrapper db_wrapper(db_object_ptr);
db_wrapper->f();

      

0


source


There seem to be two views on this CDbObject

: the "client code" view, which considers it non-volatile, and the server connection, which receives updates for the object.

So why not save CDbObject*

(which can be written) at the database level and provide the client with a pointer const CDbObject*

to it? This solves the need for different views.

struct CDataBaseLayer {

   // map of mutable objects
   typedef std::map< CDbObject::key, CDbObject*> objectmap;
   objectmap objects;

   // retrieval of non-writeable objects
   const CDbObject* readObject( CDbObject::key key ) {
      objectmap::iterator it = objectmap.find( key );
      if( it == objectmap.end() ) {
        return fetchObject( key ); 
      } else { 
        it->second->refresh();
        return it->second; 
      }
   }
};

      

The next step CDbObject

could even implement an observer pattern to notify the client when it is updated ...

0


source







All Articles