25.2.2 转移范例(1)
C和C++(www.cppentry.com)混合编程(www.cppentry.com)的危险之一就是您的程序可能会开始失去其面向对象的特性。例如,如果一个面向对象的Web浏览器的实现使用了一个过程式的网络库,那么这个程序会混用两种范式。鉴于在这个应用程序中网络任务的重要性和数量,您可以考虑写一个过程式库的面向对象封装。
例如,假设您正在用C++(www.cppentry.com)编写一个Web浏览器,但是您在使用C语言的网络库,库中包含以下代码中声明的函数。请注意,为简洁起见,省略了HostRecord和Connection数据结构。
- // netwrklib.h
- #include "hostrecord.h"
- #include "connection.h"
- // Gets the host record for a particular Internet host given
- // its hostname (i.e. www.host.com)
- HostRecord* lookupHostByName(char* inHostName);
- // Connects to the given host
- Connection* connectToHost(HostRecord* inHost);
- // Retrieves a web page from an already-opened connection
- char* retrieveWebPage(Connection* inConnection, char* page);
netwrklib.h接口相当简单明了。然而,它不是面向对象的,一个使用这样的库的C++(www.cppentry.com)程序员肯定会觉得很别扭。这个库没有组织成一个内聚的类,甚至没有正确使用const。当然,一个有才华的C程序员可以写一个更好的接口,但作为一个库的用户,您必须接受您所得到的。您有机会编写一个封装来自定义这个接口。
在我们为这个库构建面向对象的封装之前,看一下这个库是如何使用的,这样才能真正理解使用的方法。下面这个程序通过netwrklib库获取www.wrox.com/index.html页面:
- #include <iostream>
- #include "netwrklib.h"
- using namespace std;
- int main()
- {
- HostRecord* myHostRecord = lookupHostByName("www.wrox.com");
- Connection* myConnection = connectToHost(myHostRecord);
- char* result = retrieveWebPage(myConnection, "/index.html");
- cout << "The result is " << result << endl;
- return 0;
- }
让这个库变得更面向对象的一种可能方式是在查找主机、连接主机和获取网页之间提供一种识别链接的单一抽象。一个好的面向对象包装应该隐藏HostRecord和Connection类型不必要的复杂性。
这个例子遵循了第3章和第4章描述的设计原则:新的类应该捕捉库的常见用例。前一个例子展示了最常见的模式-- 首先查找一个主机,然后建立一个连接,最后获取一个页面。同样有可能需要从同一个主机获取后续页面,因此一个好的设计也要能支持这种使用模式。
下面是WebHost类公共部分的定义。这个类使得客户程序员轻松面对常见情形:
- // WebHost.h
- class WebHost
- {
- public:
- // Constructs a WebHost object for the given host
- WebHost(const string& inHost);
- // Obtains the given page from this host
- string getPage(const string& inPage);
- };
考虑客户程序员会这样使用这个类:
- #include <iostream>
- #include "WebHost.h"
- int main()
- {
- WebHost myHost("www.wrox.com");
- string result = myHost.getPage("/index.html");
- cout << "The result is " << result << endl;
- return 0;
- }