模块化程序设计

Ell*_*len 5 c modularity

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

它出现了,因为我正在尝试编写一个我想在C中实现的非常基本的浏览器,而我正在思考如何最好地实现它.基本的想法是像libcurl(用于网络交互) - > libxml2(解析HTML) - > UI然后某种方式让libcurl接受来自UI的GET或POST请求(还没有达到这一点).

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

我可以简单地为curl,libxml2等编写一个Perl或Python包装器,或者执行"curl example.com | parser | UI"这样的操作.然而,在Perl或Python中执行它仍然看起来我每次想要做一些新的事情时都必须重新编写我的程序逻辑,并且管道一切似乎都不优雅.如果可能的话,我也想在C中这样做.

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

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

2tr*_*ill 4

首先,我建议您查看http://www.amazon.com/Interfaces-Implementations-Techniques-Creating-Reusable/dp/0201498413。其次,大多数浏览器是异步的,因此您将需要一个像libuv或 之类的事件库libev。此外,大多数现代网站都需要 javascript 才能正常运行,但在浏览器中添加 javascript 引擎会使项目变得非常复杂。我也没有看到任何提及您计划如何解析发送到浏览器和从浏览器发送的 http,我建议https://github.com/joyent/http-parser

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

另请参阅函数指针,此处为多态性(C 中),此处为 C 中的函数指针如何工作?。函数指针将/可能是解决问题的更雄辩的方式,而不是在代码中使用大量的 switch 语句。使用函数指针,您可以拥有一个在程序中调用时表现不同的函数。

下面我将尝试以浏览器为例进行解释。

假设您的浏览器刚刚从某个服务器返回了 http 响应。http 响应看起来像这样C

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

    int (*decode_body)(char **);
};
Run Code Online (Sandbox Code Playgroud)

因此,首先您的 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;
}
Run Code Online (Sandbox Code Playgroud)

现在,当我们将 http 请求传递到浏览器的另一部分时,该函数可以decode_body()在 http 响应对象中调用,并且最终会得到一个它可以理解的解码正文,而无需知道它正在解码的内容。

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;
}
Run Code Online (Sandbox Code Playgroud)

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

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