VerySource

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 3883|回复: 20

结构设计问题,高手请进

[复制链接]

2

主题

13

帖子

12.00

积分

新手上路

Rank: 1

积分
12.00
发表于 2020-12-14 10:30:01 | 显示全部楼层 |阅读模式
图:
==========    =========    ========       ========
| CDevice1 |  | CDevice2|  |CDevice3| ... |CDeviceN|
==========    =========    ========       ========
      ↑           ↑          ↑            ↑
      ↓           ↓          ↓            ↓
=======================================================
|                CWhat ?                                     |
|                                                     |
=======================================================
...是这样:每一个设备类,可以理解成是操作系统的一个驱动程序!!
CWhat就是OS,要与driver实现"双向"通信: 即,CWhat要主动调Device, Device在发生中断时也要主动报给CWhat.
这个比喻与当前情形极其相似,就是底层设备与上层OS间的双向交互设计问题.

其实我这么考虑的目的有两个:
1.当某类设备硬件更新时,我能很容易的把CDeviceX替换掉,而不需修正系统的其他模块(即松散藕合)
2.CWhat这个心脏级的控制核心要在松散的基础上保持简洁,不要复杂.
回复

使用道具 举报

0

主题

70

帖子

42.00

积分

新手上路

Rank: 1

积分
42.00
发表于 2020-12-14 19:30:01 | 显示全部楼层
不好意思,你可看这段代码,然后说说为什么不适合你


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

使用道具 举报

0

主题

15

帖子

13.00

积分

新手上路

Rank: 1

积分
13.00
发表于 2020-12-15 00:45:01 | 显示全部楼层
可不可以这样, 既然和CWhat打交道的设备是如此多, 差异如此到, 可不可以单独抽象出一个类,如IDevControl, 用来实现对各个设备的不同的控制, 就是说CWhat把对各个Device的控制委托给这个设备控制接口来完成:

struct IDevControl
{
     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去处理


回复

使用道具 举报

0

主题

70

帖子

42.00

积分

新手上路

Rank: 1

积分
42.00
发表于 2020-12-15 09:15:01 | 显示全部楼层
有看了看你的原帖,发现你有一个问题,就是你说,你无法为所有的具体的设备抽象一个公共接口类,这是错误的,公共接口类本事就是描述一类事务相同的部分,既然你的系统中存在多种设备,那么寂然都是设备就必然具备一些大家都有的公共特性,否则就不是一类了,个人建议你好好把你的设备特性划分以下应该就能看出公共特性了,如果你依旧坚持你的观点,我想你的问题就不是面向对象所解决的问题(多说一句阿,你是不是从C出身的啊)
回复

使用道具 举报

2

主题

13

帖子

12.00

积分

新手上路

Rank: 1

积分
12.00
 楼主| 发表于 2020-12-15 14:00:01 | 显示全部楼层
to:爱德华德
呵呵,代码写的很详细.老兄辛苦了. 说说自己的看法,不妥的地方希望多多指教.
先说单件,在这里的情形中,我对它不支持,也不反对.
不支持: 一是它的穿透力太强,在每个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出身,只是实际工作有点硬件倾向.
回复

使用道具 举报

0

主题

70

帖子

42.00

积分

新手上路

Rank: 1

积分
42.00
发表于 2020-12-15 15:00:01 | 显示全部楼层
对于单件或不单件如你所说取决于具体的实现,这个在你的方案中它并不重要。

再说IDevice的问题. 不能因为咱们称呼一声"设备",就一定就得到一个非常美好的IDevice出来,
这是理想啊. 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;
    ....
}




回复

使用道具 举报

0

主题

70

帖子

42.00

积分

新手上路

Rank: 1

积分
42.00
发表于 2020-12-17 18:15:01 | 显示全部楼层
错上面的 ISoundDevice 和 IVideoDevice 是需要派生自 IDevice 的
回复

使用道具 举报

0

主题

70

帖子

42.00

积分

新手上路

Rank: 1

积分
42.00
发表于 2020-12-17 22:15:01 | 显示全部楼层
要费心考虑同步问题. 太多的Device均具备自己的线程, 都回调CWhat的话, 同步..对单件
来讲不仅在构造析构里要加锁同步,而且在OnDeviceInterrupt(void*)考虑更复杂的同步问题: 不能一把锁锁死,那样并发时10多个线程都在排队等待,这样效率太低,不能这么做啊.

**************************************************************
呵呵,我也是啊,说错了也请大家指正

如果你只使用在系统中只存在一个 CWhat 的话,无论你怎么做都会面临同步的问题,
如果每个设备都是用一个独立的 CWhat 的话就不存在你说的问题了,把 IDeviceX 派生自 CWhat 不就行了吗?
回复

使用道具 举报

2

主题

13

帖子

12.00

积分

新手上路

Rank: 1

积分
12.00
 楼主| 发表于 2020-12-17 22:30:02 | 显示全部楼层
to:sky_hexia
我对你的意思理解的不知道正不正确,是不是这样:
==========    =========    ========       ========
| 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...时简单了,但整个架构膨胀太大了,考虑考虑...
回复

使用道具 举报

2

主题

13

帖子

12.00

积分

新手上路

Rank: 1

积分
12.00
 楼主| 发表于 2020-12-18 14:15:02 | 显示全部楼层
to:爱德华德
呵呵,老兄够逗的.
对于抽象层次来讲,我的观点是够用就好,不能过,过犹不及.
抽象的本质,就是共性嘛. 只要够成足够的共性,就可以抽成一层.
但对于抽象往往有个误区,不考虑系统实际运行情况,但凭意识去做抽象工作,
这样抽的层次往往不是高了,就的低了.

呵呵,我也是这么过来的,做系统往往需要权衡,怎么着让它松散,怎么让它简洁,怎么让它性能高效,
三者之间如何平衡才对系统真正最优,在些关键系统里,是常常要仔细考虑的.
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|CopyRight © 2008-2023|verysource.com ( 京ICP备17048824号-1 )

快速回复 返回顶部 返回列表