数据与程序分离——程序中那些表的事儿

我们先来看一小段程序:

const char *GetString(int key)
{
    if (key == 1)
        return "first";
    else if (key == 2)
        return "second";
    else if (key == 3)
        return "third";
    else if (key == 4)
        return "forth";
    //...
    return "none";
]

这是我们经常会看到的一段程序,设计模式中著名的工厂方法。它封装了将“材料”生产成“产品”的过程,使程序更加容易读懂,并方便后期修改(易读性与可维护性)。当然,在“产品”很少的时候,这样的程序又简明又易写,很是适合。但当我们的工厂逐渐变大,产品的种类越来越多的时候,你就不得不写上一堆又一堆的 else if 了,这可是非常麻烦和烦人的一件事。后期修改的时候,读程序的人也会不禁咒骂之前的作者——这样的意大利面条可不是谁都愿意吃的。


没错,当面对这种情况时,你马上会想到用 switch 来代替。你很聪明,switch 从形式上,确实要比 else if 明了得多了,但是它也有一个缺点:如果 key 变为了非整型或 char 型,又该怎么办?

 

这个时候,我们会想到,如果有一种方法,能将数据与程序分离开,每次出现新产品,只需要将产品的样式填到菜单里就可以,那多好。啊,数据库,它可以很方便地管理这些字段。这是个好的建议,当数据项和数据量多到一定程度时,使用数据库几乎成为必然手段。然而,我们面对的却是一种尴尬的情况:问题的规模不适合用 else if 和 switch 处理,如果使用数据库,且不说运行效率,仅从操作的麻烦程序上来说,还不如直接写 else if 了。。。所以在这里,我们需要的不是强大却麻烦的大型数据库,我们需要的,仅仅是编程上的一点小技巧。说到这里,也许您已经明白了,没错,就是在程序中实现一个数据表与查询方法。查询方法只按固定的方式去数据表中查询对应项的数据,然后返回。这样,既不必连接消耗资源的数据库,提高程序运行效率,又可以明了简便地完成我们想要的模式。查询方法很简单,只要给一个数据结构,遍历就是了,那么表呢?用什么来实现?对,在C中,数组是一个必然的选择。表是二维的,那么用二维数据吗?显然不行,二维数据只能维护一堆数据类型相同的数据,这显然不符合我们的需要。我们是要将int型数据对应为string型的。于是我们想到了一个利器:结构体数组。

 

那么让我们来改写一下之前的代码:

#define END 9999

typedef struct {
    int key;
    char *str;
}ITEM;

const ITEM table[] = {
    {1, "first"},
    {2, "second"},
    {3, "third"},
    {4, "forth"},
    //...
    {END, NULL}
};

const char *GetString(int key)
{
    for (int i = 0; table[i].key != END; i++) {
        if (table[i].key == key)
            return table[i].str;
    }
}

table维护了数据的对应,而GetString只是遍历table去查找相应项。每当产品增加时,我们只需要在table中添加一个对应项即可。这样就解决了我们所面对的用 else if  和 switch 不足,用数据库又有余的数据对应问题。

同样的方法也适用于Java。Java中使用枚举来替代结构体数组。

posted @ 2012-05-30 09:57  倾越  阅读(2012)  评论(0编辑  收藏  举报