雷淼森ID:leimiaomiao
4211次访问,排名19623好友1人,关注者3
Wince软件以及驱动开发
leimiaomiao的文章
原创 9 篇
翻译 0 篇
转载 2 篇
评论 23 篇
水木沐的公告
欢迎来访,对于本人原创之文章,如有谬误,敬请指正!请尊重作者成果。
最近评论
习习:问个问题IContact里面要修改Categories怎么做??谢谢
leimiaomiao:wellfrog:
congratulations


leimiaomiao:wellfrog:
congratulations


wellfrog33:cuiyafang212,你是在问leimiaomiao吧?^_^ 我好像没有这个问题。。。让我去查一下,你可以留下邮箱,我会把code发给你
wellfrog33:leimiaomiao, 谢谢回复!后来理解了是用rapi控制手机端安装的dll,读取短消息,实现之后觉得是满简单的。
文章分类
收藏
    相册
    存档
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    转载  把乘法变成加法(转自csdn longshanks)收藏

    新一篇: Unicode与字符集函数(来源:网络) | 旧一篇: Remote RAPI

    不要误会,不是用加法重载operator*。(做这种事情的程序员应该立刻开除)。或者任何跟计算有关的事。这里要讲的是另外一个故事。
    当你看我这篇帖子的时候,是否想过你的计算机是如何构成的?内存、主板、硬盘、cpu、显卡、显示器、光驱、键盘、鼠标等等。没错,你肯定很熟悉了。那么,你是否想过电脑厂商为了生产不同的配置的计算机,准备了多少配件吗?不好意思,我也不清楚。不过没关系,我们可以假设。假设内存规格有256、512、1G、2G四种规格(不考虑牌号,后面也一样);硬盘规格有80G、100G、120G、160G和200G五种规格;显卡有三种(假设一下,我搞不清现在有多少种显卡);cpu有五款;显示器有4种;光驱有5种;鼠标键盘就不考虑了。
    那么我们总共可以得到多少种配置呢?很简单,4*5*3*5*4*5=6000种!当然没有哪个厂商会推出6000款型号,只是假设一下。那么总共有多少配件呢?4+5+3+5+4+5=26种。也就是厂商只需管理26种配件,便可以制造出6000个机型。
    现在让我们再假设一下,当初IBM发明PC的时候,一时糊涂,没有把PC的各个组成部分组件化,所有的组成部分都是焊在一块电路板上的,包括显示器。那么如果一个厂商想获得这6000种配置的电脑,那么他们就必须直接生产,并且管理6000种不同的组件(电脑)。
    这就是差别,组件化vs非组件化:26对6000。
    好,现在回到我们熟悉的软件(开发)上来。我们在软件开发是通常也面临计算机厂商同样的问题:产品多样性的问题。即便是同一种软件,在不同的客户那里通常会有不同要求。为每一个客户开发不同的软件,明显是非常低效的。(不幸的是,这种愚蠢的行为,在业界几乎成了惯例)。顺便说明一下,这里的客户是指用你软件的人。如果你开发的是库,那么客户就是使用你的库的人。而本文主要针对的是库开发这种情况。
    假设,我们要开发一个数据库访问的包装库。为其它程序员提供方便快捷地访问数据库的能力,使他们免于和难缠的ODBC或OleDB打交道。但是,前提是我们的包装库不能像ADO.net那样折损开发人员的访问能力。
    基于这种前提,我们需要考虑数据库访问的几个基本要素。我归纳了一下,大概可以包括这么几个:游标、数据绑定、数据缓冲。为了简化,其他细枝末节暂不考虑。同时,只考虑结果集处理部分。下面,我们将考察两种不同的实现方式:OOP和GP。
    先看OOP方式。OOP方式利用多态和后期绑定提供了扩展能力和一致的接口。代码大概会是这样:
    class MyDBAccessor
    {

    virtual bool MoveNext();
    virtual bool MovePre();
    virtual bool MoveFirst();
    virtual bool MoveLast();

    virtual bool GetData(const string& field, void** data);
    virtual bool GetData(int field, void** data);
    virtual bool SetData(const string& field, void* data) {…}
    virtual bool SetData(int field, void* data) {…}

    virtual void BindColumn(const string& field, DBType type);
    virtual void BindColumn(int field, DBType type);

    private:
    virtual void DefaultBind()=0;

    };
    因为这里只关心程序的结构,所以只给出声明,略去定义。MyDBAccessor定义了一个基本的框架,对于不同的特性支持,比如不同的游标等等,通过在继承类中重载相应的虚函数实现:
    class MyDBFFAccessor//Fast-forward游标类型
    : public MyDBAccessor
    {

    virtual bool MoveNext(){…}
    virtual bool MovePre(){…}
    virtual bool MoveFirst(){…}
    virtual bool MoveLast(){…}

    };
    那么,当我们需要一个支持Fast-forward游标,自动绑定,并且按行缓冲的数据库访问类时,我们定义了如下的类:
    class MyDB_FF_Dyn_Row
    : public MyDBAccessor
    {

    virtual bool MoveNext(){…}
    virtual bool MovePre(){…}
    virtual bool MoveFirst(){…}
    virtual bool MoveLast(){…}

    virtual bool GetData(const string& field, void** data) {…}
    virtual bool GetData(int field, void** data) {…}
    virtual bool SetData(const string& field, void* data) {…}
    virtual bool SetData(int field, void* data) {…}

    private:
    virtual void DefaultBind(){…}

    };
    如果我们需要一个支持Dynamic游标,字符串绑定(所有类型转换成字符串),块缓冲的数据库访问类,那么就再定义一个继承类。
    问题来了,游标类型至少有8种,假设默认绑定方式有5种(自动、宽/窄字符串绑定、xml绑定、手工绑定),数据缓冲方式有3种(行缓冲、块缓冲、数组缓冲)。
    那么我们得定义多少个继承类呢?8*5*3+1=121。Mission Impossible,除非你有ms那样的资源。
    现在,我们来看看GP(范型编程)方式会不会好一些。我们先定义一个类模板:
    template<class Cursor, class Binder, class RowBuffer>
    class MyDBAccessor
    : public Cursor, public Binder, public RowBuffer
    {

    };
    应该看出来了吧,模板MyDBAccessor继承自模板类型参数Cursor、Binder、RowBuffer。而这三个模板参数分别对应了游标管理类、绑定类和行缓冲类。根据前面的假设,我们定义了8种游标管理类:
    class FastForwardCursor
    {
    public:
    bool MoveNext();
    bool MoveLast();
    bool GetData(const string& field, void** data);
    bool GetData(int field, void** data);
    bool SetData(const string& field, void* data) {…}
    bool SetData(int field, void* data) {…}
    };
    class FastForwardReadOnlyCursor
    {
    public:
    bool MoveNext();
    bool MoveLast();
    bool GetData(const string& field, void** data);
    bool GetData(int field, void** data);
    };

    class DynamicCursor
    {
    public;
    bool MoveNext();
    bool MovePre();
    bool MoveLast();
    bool MoveFirst();
    bool GetData(const string& field, void** data);
    bool GetData(int field, void** data);
    bool SetData(const string& field, void* data) {…}
    bool SetData(int field, void* data) {…}
    };
    细心的人会发现这些游标管理类的接口(成员声明)都不一样,一会儿会告诉你为什么。
    其他的绑定类和数据缓冲类都依次定义。当我们需要一个支持Fast-forward游标,自动绑定,并且按行缓冲的数据库访问类时,只需用相应的类实例化模板即可:
    MyDBAccessor<FastForwardCursor, DynamicBinder, SingleRowBuffer>da;

    如果我们需要一个支持Dynamic游标,字符串绑定(所有类型转换成字符串),快缓冲的数据库访问类,也很方便:
    MyDBAccessor<DynamicCursor, StringBinder, BulkBuffer>da;

    在GP方式中,我们只需定义8+5+3+1=17个类和模板,即可实现OOP方式中121类定义才能达到的效果。
    非常好吧。还不止于此。假设你希望用DynamicCursor游标访问数据库,但是写错了变成了这样:
    MyDBAccessor<FastForwardCursor, DynamicBinder, SingleRowBuffer>da;

    da.MoveFirst();//啊呀!
    不要告诉我你不会犯这种低级错误。这种错误每时每刻都在发生,最可能的一种情况就是软件的设计改了,由fast-forward游标改成dynamic游标,而你却忘了修改da的声明。
    此时,代码不会编译通过。因为MyDBAccessor继承自游标管理类,并从游标管理类继承了操纵游标的成员函数。于是,根据fast-forward的定义:只进不退,所以没有MoveFirst()函数(也不需要,对吧)。因此,MyDBAccessor<FastForwardCursor, DynamicBinder, SingleRowBuffer>也没有这个函数。那么da.MoveFirst()便会引发编译错误。
    很多初学者可能不喜欢这种设计,因为他们非常害怕编译器错误。就好像编译器是他们中学语文老师一样。其实,你应该感谢这个编译错误,它在第一时间帮你消除了一个潜在的bug。如果我们在FastForwardCursor中加上MoveFirst()这个函数,编译自然没有问题。但在运行时,这句代码肯定会引发一个运行时错误。运气好的话在你测试的时候,运气不好的话可能会在你客户心情最差的时候发生。这个后果,…,哎呀呀。
    另外,即使在你测试的时候发生,你也会被迫用几十上百个单步追查问题的原因,以至于把你周末约会女朋友的心情都搞坏了。&#61514;
    好了,乘法变加法的把戏变完了。简单地讲,就是你可以利用模板、继承模板参数,以及多继承等技术,将一些基本的要素组合起来,构成一个复杂的,功能完整的类。用最少的代码作最多的事。这种技术是由C++领域的先锋官Andrei Alexandresu提出来的,称为policy。更详细的内容,可以参考他的《Modren C++ Design》,里面有很详细的讲解和案例。不过得做好心理准备,接受大剂量模板。

    发表于 @ 2007年05月07日 10:10:00|评论(loading...)|编辑

    新一篇: Unicode与字符集函数(来源:网络) | 旧一篇: Remote RAPI

    评论:没有评论。

    发表评论  


    登录
    Csdn Blog version 3.1a
    Copyright © 水木沐