模块化程序设计

时间:2015-05-14 21:19:12

标签: c modularity

不幸的是,我的问题很糟糕,因为我并不完全肯定会打电话给我试图做的事情。我为此道歉。

它出现了,因为我试图编写一个我想在C中实现的基本浏览器,而我正在思考如何最好地实现它。基本思想就像libcurl(用于网络交互) - > libxml2(解析HTML) - >用户界面以及某种方式让libcurl接受来自用户界面的GET或POST请求(尚未达到这一点)。

然而,这个approuch是非常有限的,如果我说要检查它是否是PDF然后将它发送到libpoppler然后再交给libxml2我将不得不重新编码我的整个程序流程。此外,如果我想使用我的程序的一部分(例如,libcurl - > pdftohtml - > libxml2部分)并将其发送到另一个程序(例如w3m而不是我的UI),我再次不要看看我将如何管理它。

我可以简单地为curl,libxml2等编写一个Perl或Python包装器,或者按照" curl示例做一些事情。解析器| UI&#34 ;.然而,在Perl或Python中执行此操作似乎仍然需要每次我想要做一些新的事情时重新编写我的程序逻辑,并且管道一切看起来都不够优雅。如果可能的话,我也想在C中这样做。

所以我的问题是;人们怎么称呼这个想法?我一直在疯狂地试图弄清楚如何寻找一个我无法命名的问题的解决方案。我知道它与模块化有关,但是我不知道具体的和模块化是非常的广义术语。其次,如果有人能指出解决方案,我会很感激,尽管它并不像它所说的那样重要。

感谢所有阅读此内容的人。 :)

1 个答案:

答案 0 :(得分:4)

首先我建议你看一下http://www.amazon.com/Interfaces-Implementations-Techniques-Creating-Reusable/dp/0201498413。第二大多数浏览器都是异步的,因此您需要一个事件库,如libuvlibev。此外,大多数现代网站都需要javascript才能正常运行,但在浏览器中添加javascript引擎会使项目复杂化。我也没有看到你计划如何解析发送到浏览器和从浏览器发送的http,我建议https://github.com/joyent/http-parser

关于控制流的问题,我将有一个函数解析来自服务器的响应,并使用switch()来处理发送到浏览器的各种类型的数据。 http标题中有一个字段,用于解释内容类型以及浏览器应该能够根据内容类型调用不同函数的方式。

另请查看函数指针,Polymorphism (in C)How do function pointers in C work?。函数指针将/可能是一种更有说服力的方法来解决您的问题,而不是在您的代码中使用大型switch语句。使用函数指针,您可以拥有一个在程序中调用时表现不同的函数。

我将尝试以浏览器为例进行说明。

因此,假设您的浏览器刚刚从某个服务器获取了http响应。 http响应在C中看起来像这样。

struct http_res
{
    struct http_header *header;
    struct http_body *body

    int (*decode_body)(char **);
};

首先你的http解析器将解析http头并找出它是否是一个有效的响应以及是否有内容等等。如果有内容,解析器将检查类型并基于关闭,如果它是html,javascript, css,或者解析器将函数指针设置为指向右侧函数以解码http正文的任何​​内容。

static int decode_javascript(char **body)
{
    /* Whatever it takes to parse javascript from http. */
    return 0;
}

static int decode_html(char **body)
{
    /* Whatever it takes to parse html from http. */
    return 0;
}

static int decode_css(char **body)
{
    /* Whatever it takes to parse css from http. */
    return 0;
}

int parse_http_header(struct http_res *http)
{
    /* ... lots of other code to figure out content type. ... */

    switch(body_content_type)
    {
        case BCT_JAVASCRIPT:
          http->decode_body = &decode_javascript;
          break;

        case BCT_HTML:
          http->decode_body = &decode_html;
          break;

        case BCT_CSS:
          http->decode_body = &decode_css;
          break;

        default:
          printf("Error can't parse body type.\n");
          return -1;
    }
    return 0;
}

现在,当我们将http请求传递给浏览器的另一部分时,该函数可以在http响应对象中调用decode_body(),并且最终会得到解码后的主体,它可以理解,而不知道它在解码什么。

int next_function(struct http_res * res)
{
    char *decoded_body;
    int rtrn;

    /* Now we can decode the http body with out knowing anything about
    it. We just call decode_body() and end up with a buffer with the
    decoded data in it. */
    rtrn = res->decode_body(&decoded_body);
    if(rtrn < 0)
    {
        printf("Can't decode body.\n");
        return -1;
    }

    return 0;
}

要使程序至少在C中实现模块化,您可以将浏览器的各个部分粘贴在不同的共享库中,如HTTP解析器,事件库,Javascript引擎,html解析器等。然后,您将在每个库之间创建接口,并且您可以使用不同的库替换每个库,而不必更改程序,您可以在运行时链接不同的库。看看罗伯特·马丁博士(鲍勃叔叔),他对此进行了广泛的讨论。这个谈话很好,但缺少幻灯片https://www.youtube.com/watch?v=asLUTiJJqdE,从8:20开始。这个也很有趣,它有幻灯片:https://www.youtube.com/watch?v=WpkDN78P884

最后,关于Cperlpython的任何内容都意味着您必须重新编码您的程序逻辑。您必须设计程序,以便每个模块彼此不了解。模块知道接口,如果连接两个“说”相同接口的模块,您将创建一个模块化系统。就像互联网的工作方式一样,互联网上的各种计算机不需要知道其他计算机是什么,或者它正在做什么,或者它的操作系统,他们需要知道的只是TCP/IP并且他们可以与之通信互联网上的所有其他设备。