模式的思考——SSL第二个历程碑和VES项目感悟

作为项目中变化的起始点,SSL的demo发布了,代码评审也逐步开始,回顾之前的设计,感觉自己成长了许多。
学习设计模式,是从guyu推荐《设计模式精解》开始的,对于模式这样的东西,没有实践,也始终是纸上谈兵。因此在开始工作后,我都努力的寻找可以使用模式的一切机会,一有机会便想方设法利用模式去实践,现在想想当时自己都有点走火入魔的嫌疑,的确在面对伟大的技术时,我们不可能冷静,就像anxin现在对模板的痴迷一样。

先谈谈SSL中使用的设计模式吧——【单件模式】。
这个模式最好的地方是你不用担心资源的申请,最坏的地方却是要担心资源的释放。你可以在任何一个地方GetInstance,使用它,然后像对待局部变量一样将他抛弃。作为程序的作者,对于资源的申请方面,只需要考虑不要做出多于一个的实例就可以了,所以很自然会想到单件的多线程版——双重锁定模式。但是问题总是不断的涌现,作为一个对象,他被创建出来并不会高枕无忧,烦恼可能才刚刚开始。 
1.如果需要初始化,对象才能被使用,那么该如何呢?

static  _Type *  GetInstance( void )
{
    
if ( NULL == m_pInstance )
    
{
        m_CriticalSection.Enter();
//锁机制
        if ( NULL == m_pInstance )
        
{
            m_pInstance 
= new Type;
            
if ( NULL != m_pInstance )
            
{
                
if ( !m_pInstance.Initialize() )
                
{
                    delete m_pInstance;
                    m_pInstance 
= NULL;
                }

            }

        }

        m_CriticalSection.Leave();
    }

    
return m_pInstance;
}

这样貌似不错,但是却隐含了另一个致命问题。就是在m_pInstance = new Type;这句执行之后,m_pInstance已经不是NULL了,这时候再有一个请求GetInstance时,得到的指针可能还没有进行完初始化就被使用了,后果就可能会出错。也许可以把他放到构造函数中去,但是Initialize()是有可能出错的啊,如果出错,那么第二次Initialize谁来调用?所以引入一局部变量是更好的做法。

 

static  _Type *  GetInstance( void )
{
    
if ( NULL == m_pInstance )
    
{
        m_CriticalSection.Enter();
        
if ( NULL == m_pInstance )
        
{
            
static _Type objInstance;
            
if ( objInstance.Initialize() )
            
{
                m_pInstance 
= &objInstance;
            }

        }

        m_CriticalSection.Leave();
    }

    
return m_pInstance;
}

这样做还可以省去了那个判断,也可以避免上述问题。

2.还没完,资源申请的问题解决了,但是谁来释放?有了Initialize()也应该会有UnInitialize()函数吧,写这个函数不难,难的是谁来调用?谁有这个职责?《设计模式精解》里没有《深入浅出设计模式》里也没有,怎么办?其实模式告诉我们的只是一个方法,他不可能是放之四海皆准的铁律,在遇见具体问题的时候还是要做变通。原来觉得这样的话就如同老学究一样的说教,真正遇到了这样的问题,才觉得原来这都是经验之谈。我看过好几本C++的书,自己对C++的编程能力还是不如anxin来的实在,缺少的就是实践。回到释放的问题上来,也许笨拙,但是既然有GetInstance为什么没有RealseInstance?做一个这样的接口,在用户真正需要释放的时候释放掉就好了。但是什么时候是真正释放他们的时机呢?只有用户才知道。如果你的用户可能对你写的程序的原则不是很清楚,那么可以考虑想上面的static,在退出时,他会自己释放掉自己。如果感觉指针好,那么可以写一个模板之类的东西,让他容纳单件的指针,然后做出统一的像UnInitialize这样的接口,在这个模板对象退出的时候,让他依次调用对象的UnInitialize就可以了。

接下来是两个版本的SSL——【接配器模式】
很欣赏我们组对组内软件风险的屏蔽方式,就是把最底层的与驱动相关的接口封装在SSL里,这样上层依赖的软件可以屏蔽底层驱动与BIOS接口变更带来的风险。只要SSL提供的接口不便,上层只需要关心自己的逻辑即可。
驱动变了,BIOS提供的功能变了,只有SSL变,提供了新接口,其他的同往常一样。但是我们会还是面临一个问题,就是很多软件对SSL的依赖,而且要改动他太麻烦,或者造成很多不必要的工作量,怎么办?对于新的BIOS功能和驱动,SSL变是必然的事情,要兼容以前的软件,能想到的就是接配器模式,这个模式很简单,把新接口包装一下,就变成了旧接口的样子,那么那些依赖软件就不用变化了。
GOF的经典模式中还有一个和他很像——外观模式,两者都是对现有对象的“包装”,只不过外观模式通常包装一群,而适配器往往是包装一个。但是这不是它们的本质,它们的真正区别在于“意图”,适配器模式是为了把现有的几口封装成一个用户希望的接口,而外观模式所做的是简化用户对现有众多接口的操作。

最后说说VES的显卡切换——【状态模式】
SSL的活干完了,我调去缺人手的VES,刚接手显卡切换功能的时候,同事告诉我,可麻烦了,两种显卡模式,两个开关,两个对话框,两个触发显卡模式切换的事件,两个用户可能的操作(切换还是放弃)——32种状态。怎么办?如果要用ifelse判断,恐怕bug会层出不穷。
幸好看了《深入浅出设计模式》中对于状态模式的介绍。5个状态,1个状态机,设计完成。有一次,用设计模式优雅的解决了问题。但是还是会有一些思考。
1状态与状态机之间的高内聚。
如果硬要鸡蛋里挑骨头,那么状态模式里最让我觉得不舒服的就是状态与状态机的高内聚。状态从一个抽象类中派生,带来了触发状态转换的集中操作,分工清晰合理。但是在C++中,就要有friend类,状态机要转换,就要依赖状态的具体逻辑;状态要完成实质性的操作,就要依赖状态机提供的其他函数(在显卡切换的功能里就像是弹出对话框这样的操作)。这在UML图中是一个双向关联。但是仔细想想,其实他们就应该是互相依存的关系,这一点,怕是不可避免的。

2.同样是逻辑的模式——策略模式
策略模式在结构上与状态模式非常相似,但同样在“意图”上差异非常大。区分这个模式的关键在于行为是由状态驱动还是由一组算法驱动。这条规则似乎有点随意,我在用状态模式解决显卡切换时,各个状态也是一系列逻辑,也可以被称为算法。再有一种判断规则就是状态模式是对象内部的,策略模式则是在对象外部的。说的抽象些就是状态与对象结合,而策略对立与对象。

Fighting~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值