图:
========== ========= ======== ========
| CDevice1 | | CDevice2| |CDevice3| ... |CDeviceN|
========== ========= ======== ========
↑ ↑ ↑ ↑
↓ ↓ ↓ ↓
=======================================================
| CWhat ? |
| |
=======================================================
...是这样:每一个设备类,可以理解成是操作系统的一个驱动程序!!
CWhat就是OS,要与driver实现"双向"通信: 即,CWhat要主动调Device, Device在发生中断时也要主动报给CWhat.
这个比喻与当前情形极其相似,就是底层设备与上层OS间的双向交互设计问题.其实我这么考虑的目的有两个:
1.当某类设备硬件更新时,我能很容易的把CDeviceX替换掉,而不需修正系统的其他模块(即松散藕合)
2.CWhat这个心脏级的控制核心要在松散的基础上保持简洁,不要复杂.
=========================
上个贴子回复,片段:
onestation(新手) 如果不想定义太多接口可这样定义:
struct IDeviceEvent
{
virtual long OnEvent1(int nEventId, void* pSender, void* pParam){};
};
CWhat只用继承IDeviceEvent,再通过nEventId等条件判断。
===============================
ProgrameMan(我要学汇编) :
class IDevice // CWhat 调用设备的抽象借口
class IConnectPoint // 设备调用CWhat 的接口
class CWhat
{
static IConnectPoint* RegisterDevice(IDevice *ptr) // 所有的设备对象调用这个函数向 what 注册自己,同时该函数返回 一个与自己交互的接口。(此类可以实现单件模式)
}
=================================
dick_song(卡菲的伙伴)
还是觉得定一套通用的设备接口比较好,具体对于不同设备的不同操作就要看DEVICE1 、DEVICE2 等内部的封装了。
===========================
回复人:fanchka(狼仔)
to:onestation(新手)
呵呵,这种方法实现的是"单向"交互: 即,device调用CWhat.
当然在OnEvent1中,能返回去掉device1,但仅限制在OnEvent1()中, 当CWhat内部时钟触发轮询,要向device要数据时,这种方法就不足了.这就要在CWhat内部保留一份引用表,时钟一触发就回调各个设备. "双向"就是指这个意思.但我不很情愿用 "引用表",因为回调每个设备的内容不同,
可能device1要调用它的:位置,然后再调用它的速度,最后再取它的状态.而CWhat在调用期间可能要穿插其他的操作来配合device1的返回结果.所以这种情况决定了无法对所有设备抽出一个IDeviceFace这样的接口,无法实现!
呵呵,也就是说 "引用表" 并非是list<> vector<>之类的东西,而是一个个IDevice1* _dev1; IDevice2* _dev2;...
之类的东西.想像以下,那么多的设备,CWhat中存在那么多的接口指针...,唉,这就是俺"很不情愿"的原因了.
=============================
回复人:fanchka(狼仔)
to:ProgrameMan(我要学汇编)
//class IDevice // CWhat 调用设备的抽象借口
//class IConnectPoint // 设备调用CWhat 的接口
呵呵,两个接口包不住啊,要是能包住我就不头痛了.
========== ========= ======== ========
| CDevice1 | | CDevice2| |CDevice3| ... |CDeviceN|
========== ========= ======== ========
↑ ↑ ↑ ↑
↓ ↓ ↓ ↓
=======================================================
| CWhat ? |
| |
=======================================================
...是这样:每一个设备类,可以理解成是操作系统的一个驱动程序!!
CWhat就是OS,要与driver实现"双向"通信: 即,CWhat要主动调Device, Device在发生中断时也要主动报给CWhat.
这个比喻与当前情形极其相似,就是底层设备与上层OS间的双向交互设计问题.其实我这么考虑的目的有两个:
1.当某类设备硬件更新时,我能很容易的把CDeviceX替换掉,而不需修正系统的其他模块(即松散藕合)
2.CWhat这个心脏级的控制核心要在松散的基础上保持简洁,不要复杂.
=========================
上个贴子回复,片段:
onestation(新手) 如果不想定义太多接口可这样定义:
struct IDeviceEvent
{
virtual long OnEvent1(int nEventId, void* pSender, void* pParam){};
};
CWhat只用继承IDeviceEvent,再通过nEventId等条件判断。
===============================
ProgrameMan(我要学汇编) :
class IDevice // CWhat 调用设备的抽象借口
class IConnectPoint // 设备调用CWhat 的接口
class CWhat
{
static IConnectPoint* RegisterDevice(IDevice *ptr) // 所有的设备对象调用这个函数向 what 注册自己,同时该函数返回 一个与自己交互的接口。(此类可以实现单件模式)
}
=================================
dick_song(卡菲的伙伴)
还是觉得定一套通用的设备接口比较好,具体对于不同设备的不同操作就要看DEVICE1 、DEVICE2 等内部的封装了。
===========================
回复人:fanchka(狼仔)
to:onestation(新手)
呵呵,这种方法实现的是"单向"交互: 即,device调用CWhat.
当然在OnEvent1中,能返回去掉device1,但仅限制在OnEvent1()中, 当CWhat内部时钟触发轮询,要向device要数据时,这种方法就不足了.这就要在CWhat内部保留一份引用表,时钟一触发就回调各个设备. "双向"就是指这个意思.但我不很情愿用 "引用表",因为回调每个设备的内容不同,
可能device1要调用它的:位置,然后再调用它的速度,最后再取它的状态.而CWhat在调用期间可能要穿插其他的操作来配合device1的返回结果.所以这种情况决定了无法对所有设备抽出一个IDeviceFace这样的接口,无法实现!
呵呵,也就是说 "引用表" 并非是list<> vector<>之类的东西,而是一个个IDevice1* _dev1; IDevice2* _dev2;...
之类的东西.想像以下,那么多的设备,CWhat中存在那么多的接口指针...,唉,这就是俺"很不情愿"的原因了.
=============================
回复人:fanchka(狼仔)
to:ProgrameMan(我要学汇编)
//class IDevice // CWhat 调用设备的抽象借口
//class IConnectPoint // 设备调用CWhat 的接口
呵呵,两个接口包不住啊,要是能包住我就不头痛了.
class IDevice
{
public:
virtual void OnEvent(void*) = 0;
}class CDevice1
{
private:
void OnInterrupt(void* parameter)
{
CKernel::GetInstance()->OnDeviceInterrupt(parameter); }public:
virtual void OnEvent(void*)
{
}}class CDevice2
{
public:
void OnInterrupt(void*)
{ } virtual void OnEvent(void*)
{
}
}class IDeviceInterrupt
{
public:
virtual void OnDeviceInterrupt(void*) = 0;
virtual void RegisterDevice(IDevice *ptr, IDevice *root) = 0;
virtual void UnRegisterDevice(IDevice *ptr) = 0;
}
class CKernel : public IDeviceInterrupt
{
public:
static IDeviceInterrupt *GetInstance()
{
if(0 == pThis) {
pThis = new CKernel;
}
return pThis;
} public:
virtual void OnDeviceInterrupt(void *)
{
// TODO: add process device's interrupt code at here.
// this interface call by CDevice?
} virtual void RegisterDevice(IDevice *ptr, IDevice *root)
{
// TODO: add register a new or replace device code at here.
// this interface call by CDevice? if(root != 0) {
UnRegisterDevice(root);
} InternalRegister(ptr);
} virtual void UnRegisterDevice(IDevice *ptr)
{
// TODO: add unregister a device code at here.
// this interface call by CDevice?
}
private:
void fire_event(void* parameter)
{
IDevice *obj;
for(...)
{
obj = ...;
obj->OnEvent(parameter);
}
}
static IDeviceInterrupt * pThis;
}
{
LRESULT ControlDevice(enum DevTypeId id, CWhat* pWhat, ...//其它参数, 可以非常宽泛);
};
这样针对不同的设备, 实现不同的IDevControl接口, 比如:
class Dev1Controller : public IDevControl{....};
class Dev2Controller : public IDevControl{....};在CWhat内部维护一个IDevControl的引用表, 处理不同设备时, 根据设备Id, 委托相应的IDevControl完成, 因为ControlDevice(... pWhat...)引用了CWhat, 所以也可以调用CWhat的方法来辅助控制的完成.实现各个Device对CWhat的回调也可类似实现, 比如让CWhat暴露IInterruptHandler接口
struct IInterruptHandler
{
HRESULT ServiceDevice(enum DevTypeId id, ...);
}这样当CWhat收到不同Device的中断请求后, 委托给相应的Interrupt Handler去处理
呵呵,代码写的很详细.老兄辛苦了. 说说自己的看法,不妥的地方希望多多指教.
先说单件,在这里的情形中,我对它不支持,也不反对.
不支持: 一是它的穿透力太强,在每个device中出现,是不太好的主意.对于你的代码,我更喜欢这种方式:
class CDevice1:public IDevice //没误解吧? 呵呵
{
public:
CDevice1(IDeviceInterrupt* kernalFace);
protected:
IDeviceInterrupt* _kernalFace;
void OnInterrupt(void* parameter)
{
_kernalFace->OnDeviceInterrupt(parameter);
}
...
}int main()
{...; IDevice* devFace1 = new CDevice1(CKernel::GetInstance()); ...}
二者,要费心考虑同步问题. 太多的Device均具备自己的线程, 都回调CWhat的话, 同步..对单件
来讲不仅在构造析构里要加锁同步,而且在OnDeviceInterrupt(void*)考虑更复杂的同步问题: 不能一把锁锁死,那样并发时10多个线程都在排队等待,这样效率太低,不能这么做啊.
不反对: 单件是蝎子拉屎--独一份,资源消耗要小,许多调用操作简洁,如果能处理好同步问题,也算不错的选择.再说IDevice的问题. 不能因为咱们称呼一声"设备",就一定就得到一个非常美好的IDevice出来,
这是理想啊. CWhat想做的事情是非常实际的,有针对性的调用工作,就像OS告诉VGA,给我画个馅饼.
如果OS对声卡,对内存,对网卡喊"画馅饼"是讲不通的,因为VGA 声卡 内存虽然都是"设备",但从它们
所实现的功能上看,是不存在共性的. 这就是我一直所说的"这种情况决定了无法对所有设备抽出一个IDeviceFace这样的接口,无法实现!"呵呵,我不是C出身,只是实际工作有点硬件倾向.
这是理想啊. CWhat想做的事情是非常实际的,有针对性的调用工作,就像OS告诉VGA,给我画个馅饼.
如果OS对声卡,对内存,对网卡喊"画馅饼"是讲不通的,因为VGA 声卡 内存虽然都是"设备",但从它们所实现的功能上看,是不存在共性的.我想如果用面向对象的角度去考虑操作系统与设备之间关系的话,我想应该是这样的(当然操作系统是用C 和汇编实现的,在这里只是以面向对象的角度阐述一下我的想法而已)IDevice
{
public
virtual void in(...) = 0;
virtual void out(...) = 0;
virtual char * get_device_name() = 0;
}class ISoundDevice
{
public:
virtual void play(...) = 0;
virtual void setVolume(...) = 0;
...
}class IVideoDevice
{
public:
virtual draw(...) = 0;
virtual set_brightness(...) = 0;
....
}
来讲不仅在构造析构里要加锁同步,而且在OnDeviceInterrupt(void*)考虑更复杂的同步问题: 不能一把锁锁死,那样并发时10多个线程都在排队等待,这样效率太低,不能这么做啊.**************************************************************
呵呵,我也是啊,说错了也请大家指正如果你只使用在系统中只存在一个 CWhat 的话,无论你怎么做都会面临同步的问题,
如果每个设备都是用一个独立的 CWhat 的话就不存在你说的问题了,把 IDeviceX 派生自 CWhat 不就行了吗?
我对你的意思理解的不知道正不正确,是不是这样:
========== ========= ======== ========
| CDevice1 | | CDevice2| |CDevice3| ... |CDeviceN|
========== ========= ======== ========
↑ ↑ ↑ ↑
↓ ↓ ↓ ↓
Dev1Ctrler Dev2Ctrler ... ...
↑ ↑ ↑ ↑
↓ ↓ ↓ ↓
=======================================================
| CWhat ? |
======================================================
要是如此, CDevice1 回调 CWhat时, 后者可以委托Dev1Ctrler做善后工作,但,Dev1Ctrler还是
要把处理完的相关状态 写入 CWhat里面, 如果直接调pWhat写, 那么这样Dev1Ctrler Dev2Ctrler ...
与CWhat还是紧藕合关系; 如果间接调个接口..比如 IRecvState (class CWhat:public IRecvStates)
嗯...能行的通; CWhat 回调 CDevice1的时候,是由 Dev1Ctrer 完成操作,并将处理结果回写入
CWhat里面.
呵呵,感觉CWhat调用CDevice1,CDevice2...时简单了,但整个架构膨胀太大了,考虑考虑...
呵呵,老兄够逗的.
对于抽象层次来讲,我的观点是够用就好,不能过,过犹不及.
抽象的本质,就是共性嘛. 只要够成足够的共性,就可以抽成一层.
但对于抽象往往有个误区,不考虑系统实际运行情况,但凭意识去做抽象工作,
这样抽的层次往往不是高了,就的低了.呵呵,我也是这么过来的,做系统往往需要权衡,怎么着让它松散,怎么让它简洁,怎么让它性能高效,
三者之间如何平衡才对系统真正最优,在些关键系统里,是常常要仔细考虑的.
| CDevice1 | | CDevice2| |CDevice3| ... |CDeviceN|
========== ========= ======== ========
↑ ↑ ↑ ↑
↓ ↓ ↓ ↓
Dev1Ctrler Dev2Ctrler ... ...
↑ ↑ ↑ ↑
↓ ↓ ↓ ↓
=======================================================
| CWhat ? |
======================================================你画的图就是我想的, 我不过是借鉴了硬件系统中的组织结构, 在一个硬件系统中, CPU(相当于你这里的CWhat), 并不会直接操作外设的工作, 而是通过与外设相连的硬件控制器来完成的, 例如CPU不会直接控制硬盘(相当你这里的一个Device)马达的旋转, 不会控制磁头的运动, 这些是用硬盘控制器(相当于图中DevXCtrler)完成的, CPU所做的只是象不同设备的控制器"暴露"出来的端口(相当于这里的接口)写入正确的控制字, 或从中读出状态字, 所以在这种程度上, "端口"的概念进一步降低了CPU和硬件控制器的偶合.所以你说CWhat和DevXCtrler是紧偶合, 是对的, 因为这就好比CPU为了控制软盘, 要有专用软盘指令集, 为了控制硬盘又要有一套专用的硬盘指令集, 但实际上CPU并没有这些指令集, 也不可能有. 所以为了降低CWhat和DevXCtrler的偶合, 可以再模拟出端口的概念, 比如IPort.这样确实会造成代码膨胀, 但设计模式好像就是这样的, 如果通过一定代码的膨胀可以实现各个单元模块的高内聚, 低偶合, 易于维护和扩展, 那这种膨胀还是值得的. 这只是我的拙见
呵呵,我正在考虑适当的变通一下,device和CWhat间用 接口 和 DevXCtrler结合的方式, 复杂的设备用DevXCtroler处理,简单的就用接口.to:loseme915(郁闷)
呵呵,很不错的想法,有几个疑问点: 全局结构里面的存类的成员函数地址吗? 那样来实现CWhat回调Device以获取它的状态,呵呵是这个意思吧?
呵呵,遗憾的是,要回调很多个函数啊,而且参数列表也不同,这又回到"无法定义一个统一接口"问题上了. 设备发信号是个好的想法,但如果CWhat没来得及处理,而它又发了第二个信号,这个设备的前后两个状态有覆盖的情形,如果用容器存储每个状态的话,唉,要很大的开销啊.系统内核级的信号切换也很耗资源啊. CWhat主动调用Device,也不好实现啊.
呵呵,不过刚开始看的时候,确实有些心动.
简单问题,要简单处理. 复杂问题也要努力简单处理,但简单始终是相对的.设计基本出来了,有时间就把代码贴上来.
无为搜索引擎开始测试了啊
(第三次开放测试啊) 网站运行后的效果请参见:
http://219.233.38.213/Search/WuWei.aspx
代码下载地址 :http://www.ofile.cn/se.rar
前两次用 CGI+html做了一个版本还做了一个 Java版本 (这次比较忙,所以没来的及更新,有需要的跟我说一声啊)
这次用 C# ASP.NET做一个 玩玩
做的不好,请大家做指教啊!
这次还实现了计算器功能啊
可以搜索一下 sin(1+2) 看看
另外 sh=1&sf=1&ua=1&sa=1&st=1&wh=1&ph=1 把这里面的 1改成 0看看 每个部分都是可以控制的:)
至于为什么要把客户端网站部分开源,请参考我第二次开放测试时即兴写的文章 : 最近我研究搜索引擎 七 (长长中国人的志气篇)
http://www.baidu.com/s?wd=%D7%EE%BD%FC%CE%D2%D1%D0%BE%BF%CB%D1%CB%F7%D2%FD%C7%E6%C6%DF&cl=3
承盟广大网友看的起 该文目前已经被全国 2000多网站转载
先说一下技术指标: 本次我收录了全国30多万个一、二级域名, 网页采集用了三周时间,目前已经采集了 12万网站,平均每个网站收录 30篇网页,索引进行了 10天,
目前已经索引了 100多万网页 。 搜索核心部分采用这次采用 C 语言开发。 客户端提供三个版本一个CGI+HTML版本,一个 Java版本,一个 ASP.NET版本。代码下载地址 :http://www.ofile.cn/se.rar
搜索网站客户端(.NET版本)整体解决方案(源代码)
(第三次开放测试啊) 网站运行后的效果请参见:
http://219.233.38.213/Search/WuWei.aspx
struct IDeviceEvent
{
virtual long OnEvent1(int nEventId, void* pSender, void* pParam){};
};
CWhat只用继承IDeviceEvent,再通过nEventId等条件判断。呵呵,抽象过头了工作量太大,不要和自己过不去啊,你看看 Office 的插件实现方式,应该会有不少收获
下面的代码没有整理,大体能说明一下思路.
interface IStateSender
{
virtual BOOL InitSender() = 0;
virtual void OnReportState() = 0;
virtual void OnReportStateWithMsg(DeviceMsg devMsg, /*OUT*/ void* data) = 0;
virtual void RegStateCollector(IStatesCollector* pCollector) =0;
virtual int ToDoWork(DeviceMsg devMsg, /*IN*/ void* data) = 0;
virtual DevType SenderType() = 0;
};interface IStatesCollector
{
virtual int OnRecvedDevMsg(DeviceMsg devMsg, void* pParam) = 0;
virtual void RegStateSender(IStateSender* pSender) = 0;
virtual void RegStatesCollector(IStatesCollector* pCollecter) = 0;
};class CDispatchCenter : public IStatesCollector //it's CWhat.
{
public:
static CDispatchCenter* Instance();
static void Release(); virtual int OnRecvedDevMsg(DeviceMsg devMsg, void* pParam) ;
virtual void RegStateSender(IStateSender* pSender);
virtual void RegStatesCollector(IStatesCollector* pCollector);protected:
CDispatchCenter();
virtual ~CDispatchCenter(); void OnSocketMsg(_tagCommuCmd* pParam);
void DispatchMsg(DeviceMsg devMsg, void* pParam);protected:
static CDispatchCenter* _instance;
IStateSender* _arrSender[Dev_Count];
list<IStatesCollector*> _lstCollector;
CRealTimeStates* _rts; typedef list<IStateSender*>::iterator SenderIterator;
typedef list<IStatesCollector*>::iterator CollectorIterator;
};enum MotorDeviceMsg
{
MDMsg_Nothing =-1,
MDMsg_AutoRun =0,
MDMsg_ManuRun,
MDMsg_Stop,
MDMsg_ArrivedStation,
MDMsg_IncSpeed,
MDMsg_DecSpeed,
MDMsg_TurningByAngle,
MDMsg_Count,
};typedef struct _tagMotor_A2D_Msg //A2D: application to device
{
MotorDeviceMsg msg;
BOOL isStation;
MovedControl mc;
MotorStatues ms[M_Count];
} MotorMsgArg;class CMotorProxy : public IStateSender
{
public:
CMotorProxy();
virtual ~CMotorProxy(); virtual BOOL InitSender() ;
virtual void OnReportState();
virtual void OnReportStateWithMsg(DeviceMsg devMsg, void* data);
virtual void RegStateCollector(IStatesCollector* pCollector) ;
virtual int ToDoWork(DeviceMsg devMsg, /*IN*/ void* data) ;
virtual DevType SenderType();protected:
CMotor* _motor;
IStatesCollector* _collecter;};class CCmdProxy : public IStatesCollector
{
public:
static CCmdProxy* Instance();
static void Release(); void OnSocketMsg(INT nCmd, const char* data, int len);
virtual int OnRecvedDevMsg(DeviceMsg devMsg, void* pParam);
virtual void RegStateSender(IStateSender* pSender){}
virtual void RegStatesCollector(IStatesCollector* pCollecter);protected:
CCmdProxy();
virtual ~CCmdProxy(); void AutoRunTask(const char* data, int len);
void ManualRunTask(const char* data, int len);
void PantiltTask(const char* data, int len);
void IOCtrlTask(const char* data, int len);
void CameraTask(const char* data, int len);
void AudioTask(const char* data, int len);
protected:
static CCmdProxy* _instance;
IStatesCollector* _dispCenter;
};