2

抱歉,我想不出这个问题的好标题...

在应用程序启动时,我通过数据库访问库从数据库加载对象,让我们调用它们的类CDbObject

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

protected:
    CState m_state;
}

在运行时,我收到与这些数据库对象中的状态更改相对应的消息。
我想最小化数据库访问,因此当它的状态改变时不重新加载完整的对象。
相反,我想包装 DB 对象并以某种方式使它们可修改。
我不能简单地派生一个类、实现一个setState()方法并创建该类的对象,因为我必须使用 DB 访问库给我的对象。这些对象没有实现复制机制,如果可能的话,我根本不想碰那个代码。

我可以创建一个包装类来存储指向 CDbObject 实例的指针,如下所示:

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;
}

但明显的缺点是,我必须复制包装类的完整接口。
为了避免重复接口,我可以提供对包装对象的访问,但这使得包装器实际上毫无用处,因为如果用户不够谨慎,他可能会得到错误的状态。

有没有一种优雅的方式来完成我想要的?

编辑:

简而言之:我想让它对存储对象状态的用户透明。用户应通过调用一种方法获得当前状态。我希望这使它更清楚一点。

4

3 回答 3

1

我和 Jason 在一起,一个派生自 CDbObject 的类很容易解决问题,除非这些对象来自一些不透明的接口。

但是,如果您的应用程序崩溃,并且这些状态没有写回数据库,那会造成什么样的破坏?很多时候数据库是为了持久性而存在的,如果你删除/隐藏了持久性,你能优雅地恢复吗?

于 2009-08-28T16:23:37.140 回答
0

似乎对此有两个视图CDbObject:“客户端代码”视图,它认为它是不可更改的,以及服务器连接,它接收对象的更新。

那么为什么不在CDbObject*数据库层保留一个(可写的),并为客户端提供指向它的const CDbObject*指针呢?这解决了对不同视图的需求。

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; 
      }
   }
};

在更进一步的阶段,CDbObject甚至可以实现一个观察者模式来在更新时通知客户端......

于 2009-08-31T13:43:40.767 回答
0

您可能会发现 operator-> 很有用。根据您希望在处于无效状态时调用函数时的行为,将此函数添加到 CWrapper:

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

或这个:

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

然后使用类似于 auto_ptr 的包装器:

CWrapper db_wrapper(db_object_ptr);
db_wrapper->f();
于 2009-08-28T16:19:47.257 回答