【LibUIDK界面库系列文章】值改变时可发出通知的通用数据类型

本文介绍了一种基于C++模板类的设计模式,该模式能够实现在数据发生变化时自动通知所有关注该数据变化的对象,无论这些对象是否为视图类。通过重载赋值操作符并在其中触发回调机制,使得数据的更新变得透明且高效。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



作者:刘树伟


我们设想这样一种应用: 一类整形数据int a, 有10个窗口A1 --- A10会显示它, 另有一个窗口B可编辑它. 当B编辑完a后, 窗口A1 --- A10需要刷新a, 这是典型的"文档/视"模型, 用MFC类CDocument和CView来实现是这样的: CDocument的派生类保存a, 把窗口A1到A10和窗口B作成CView的派生类, 通过CDocument::AddView把这11个窗口加到文档中, 当窗口B修改a以后, 调用CDocument::UpdateAllViews刷新所有视图, 来更新a. 这是一种常用的方法, 但有些弊端, 首先如果显示a的窗口不是CView的派生类, 将得不到刷新的机会; 其次B修改A后, 要主动调用UpdateAllViews, 才能刷新所有视图; 最后, 如果没有文档/视支持, 将不能使用这种方法, 比如控制台程序, 或者使用其它应用程序框架创建的程序.

我们可以抽象"文档/视"这一结构, 使a变化的时候, 自动通知需要得知这一变化的对象, 而不用关心是谁修改了a, 并且被通知的对象也不局限CView的派生类对象.

一个对象被修改, 通常是执行"="操作, 我们可以通过C++的模板类, 包装任意类型的对象, 然后重载"="操作符, 当通过调用operator=来修改a的值时, 在operator=中我们可以通过回调函数的方法, 来执行用户传入的回调函数. 而这些回调函数, 正是用户需要在a改变时, 执行的函数.

以下是抽象后的C++类模板.

template<typename T>
class CNotifyType
{
public:
 typedef int (*CNotifyTypeChanged)(const T &rOld, const T &rNew, long lParam);
 CNotifyType()
 {
 }
 CNotifyType(const CNotifyType &v)
 {
  _value = v;
 }
 ~CNotifyType()
 {

 }

 const CNotifyType& operator=(const T& v)
 {
  T old = _value;
  _value = v;

  if (old != _value)
  {
   int nSize = m_vf.size();
   for (int i=0; i<nSize; ++i)
   {
    pair<CNotifyTypeChanged, long> *f = &m_vf[i];
    if (f->first != NULL)
     (f->first)(old, _value, f->second);
   }
  }
  return *this;
 }
 operator T () const
 {
  return _value;
 }

 void RegisterNotifyCallback(CNotifyTypeChanged f, long lParam)
 {
  pair<CNotifyTypeChanged, long> p(f, lParam);
  m_vf.push_back(p);
 }

 void UnregisterNotifyCallback(CNotifyTypeChanged f)
 {
  int nSize = m_vf.size();
  for (int i=0; i<nSize; ++i)
  {
   pair<CNotifyTypeChanged, long> *f = &m_vf[i];
   if (f->first != f)
   {
    m_vf.erase(m_vf.back() + i);
    break;
   }
  }
 }

private:
 T _value;
 vector<pair<CNotifyTypeChanged, long> > m_vf;
};

// example
int Notify(const CString &rOld, const CString &rNew, long lParam)
{
 ASSERT(lParam == 123);
 return 0;
}

int Notify2(const CString &rOld, const CString &rNew, long lParam)
{
 ASSERT(lParam == 456);
 return 0;
}

CNotifyType<CString> a;
a.RegisterNotifyCallback(Notify, 123);   // 相当于AddView
a.RegisterNotifyCallback(Notify2, 456);
a = _T("abc"); // auto call Notify and Notify2  // 内部相当于调用UpdateAllViews

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值