windows程序设计(23):比较3种单文档程序的架构

第一个是我们之前讲过的方块程序,它的调用关系大致如下:



第二个是一个简单的股市软件的程序,比较长,这里就不贴出代码了,说一下大概的思路:
有一个专门的硬件和配套的驱动、动态链接库。通过动态链接库中的函数,可以将从射频接收到的消息与windows的一个自定义消息绑定,绑定以后,就可以通过消息响应函数OnIRQ来获取消息。通过GetActiveDocument 获得文档类指针,把数据放在文档类中的m_stock中。然后通过GetActiveView获取视类指针,调用视类的Invalidate函数,这个函数引起操作系统发送一个WM_PAINT消息,这个消息会调用视类的OnPaint函数,进而调用OnDraw函数。而OnDraw想要绘图,必须通过GetDocument获取文档类的指针,拿到文档中的数据进行绘图。架构如下:



与第一个程序相比,最大的区别在于这个程序缺少了对数据的保护。数据时public的,并没有通过接口访问。所以程序如果需要改进或者升级,那么需要修改的地方非常多;如果对数据的访问提供了接口,那么只要接口不变,则调用接口的函数就不需要做太大的修改。而且如果提供了接口,那么想要动数据,必须通过接口,这样数据会更加安全。


下面看一个更加复杂的股市软件程序,它使用了多线程技术,路线图画的稍微有点特别,主要强调的是线程间的关系,不是类的关系。


首先,应用程序和框架类组成了整个程序的主线程。在OnCreate中创建了两个线程。一个线程由CUIFrameWnd和CUIThread组成,这类线程成为UI线程,它们有窗口,可以接收消息,我们的数据接收响应函数OnIRQ就放在里面,另一个线程ReadRingThread是一个worker线程,没有窗口,用来读取数据。当每次接收数据以后,调用读环线程来读取数据,储存在另一中数据结构,用来储存和显示当前和历史的数据。读取完毕后再将线程睡眠。
这个程序的奇妙之处在于,虽然OnIRQ和ReadRingThread都操作了数据,但是并没有使用使用线程同步机制来保护数据,这是为什么呢?因为设计者把数据设计成了一个环,读取数据时,只能读取当前写入位置之前的某个位置的数据。所以读写操作始终不会操作同一个内存地址。

这里补充几句关于这个股市软件的数据结构的设计,其实是有大学问的。接收下来的包是一种固定的格式,通过包的类型判断是指数还是某个股票,还是某个信息等等。
但是这些信息中,有的是需要长久储存的,比如每个股票的每一分钟的价格、成交量之类的;有的信息是不需要储存的,比如当前时刻的买一买二买三之类的。而且股市中的股票数量是不断变化的。考虑到这些因素,所设计的数据结构应该是这样:

typedef struct
{
	float	New;
  	float	Amount;
    float   Volume;	
	CTime	Time;
}STORAGE;//------------------------------------------------------------实时数据存储数据结构


typedef struct
{
	float	LastClose;
	float	Highest;
    float   Open;
	float	New;
    float   Lowest;
	float	Volume;
	float	Amount;
	float	Pbuy1;
	float	Vbuy1;
	float	Pbuy2;
	float	Vbuy2;
	float	Pbuy3;
	float	Vbuy3;
	float	Pbuy4;
	float	Vbuy4;
	float	Psell1;
	float	Vsell1;
	float	Psell2;
	float	Vsell2;
	float	Psell3;
	float	Vsell3;
	float	Psell4;
	float	Vsell4;																
}REFRESH;//-------------------------------------------实时数据刷新数据结构

class CIndexStockMem/* : public CObject*///-----------构造指数和股票实时数据存储空间
{
public:
	CIndexStockMem();
	virtual ~CIndexStockMem();

//	void IsCurWindow(CString strCurCode);

	CArray<STORAGE, STORAGE> m_StorageArray;//--------实时数据存储结构体动态数组	
	REFRESH m_Refresh;//------------------------------实时数据刷新结构体变量

};

那么如何访问这些数据结构呢?应该考虑到有人是通过证券代码访问的,有人通过拼音访问,然后在增加一个指向前面所述的CIndexStockMem类的指针:

class CIndicator/* : public CObject*///构造所有指数或股票内存的索引 
{
public:
	CIndicator();
	CIndicator(CIndicator& Indicator);
	virtual ~CIndicator();

	CIndicator& operator = (CIndicator& Indicator);

public:
	CString				m_strIndicatorCode;//指数或股票的代码
	CString				m_strIndicatorName;//指数或股票的名称
	CIndexStockMem*		m_pIndexStockMem;//指向指数或股票内存的指针	
};

在原始的程序中,将缓冲区和要存储、刷新的数据都放在CUIFrameWnd了下面,而架空了原始的文档视图架构。这样的设计其实并不是十分合理的。应该把存储、刷新的数据的数据放在文档中更加合适。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值