C++“隐藏实现,开放接口”的实现方案

为什么要有接口?

接口就是一个程序与其它程序交流的窗口。就比如有一个电视机,我并不需要知道它是怎样工作的,我只要知道按电源键就可以开启电视,按节目加(+)减(-)可以切换电视频道就可以了。

Java程序员都知道Java中有interface可以实现对外的接口,但C++并没有接口这样的语法,那它要好怎样实现对外提供接口呢?我们可以通过纯虚函数定义一个抽象类,专门用来声明一个类的功能。

我们完成了一个程序模块的开发,要把这个程序模块给别人用,你肯定不会把源代码给他(那别人就完全撑屋你的技术了),你会把这个程序模块编译成一个库(静态库lib或动态库dll)再给别人用。那别人拿到你的库后怎样用呢?这就需要看你的程序所提供的接口。C++的封装性是特别好的(个人觉得比Java好多了,Java打成的jar包很容易就可以被反编译,C++要反编译就困难多了),我只要给你编译出的库和接口的头文件就可以了。



从一个实例讲讲实现方案

需要

我们先来看一个场景。假设有一个电子文档(Document)、一个文档下有多个页(Page),每个页下有多个文本单元(TextUnit,表示文档内元素的基本单位),一个文档中的所有文本单元对象都有唯一的ID。其类图关系如下:

图1 :类的关系图


设计

根据需求,我们可以定义三个类Document、Page、TextUnit分别表示文档、页、文本单元,每个类我们还需要一个对外的接口,于是需要三个对外的接口类IDocument、IPage、ITextUnit。

根据这些类我们先创建.cpp文件和.h文件,组织一下工程(EBook)目录结构如下:

图2: 工程目录结构

这里Document、Page、TextUnit就是具体的实现类,IDocument、IPage、ITextUnit就是对外提供的接口,这样就实现了实现与接口分离。


代码实现

IDocument.h:

#pragma once

class IPage;

class IDocument
{
public:
    virtual ~IDocument(void){}

public:

    //---------------------------------------------------------------
    //function:
    //          GenerateId 生成本文档内唯一的文本对象ID
    //Access:
    //          virtual  public
    //Parameter:
    //Returns:
    //          int - 返回ID
    //Remarks:
    //          ...
    //author:    luoweifu
    //---------------------------------------------------------------
    virtual int GenerateId() = 0;

    //---------------------------------------------------------------
    //function:
    //          AddPage 添加一页
    //Access:
    //          virtual  public
    //Parameter:
    //Returns:
    //          IPage* - 返回页对象
    //Remarks:
    //          ...
    //author:    luoweifu
    //---------------------------------------------------------------
    virtual IPage* AddPage() = 0;
};

IPage.h:

#pragma once

class ITextUnit;

class IPage
{
public:
    virtual ~IPage(void){}

public:

    //---------------------------------------------------------------
    //function:
    //          AddTextUnit 添加一个文本单元
    //Access:
    //          virtual  public
    //Parameter:
    //Returns:
    //          ITextUnit* - 文本单元对象
    //Remarks:
    //          ...
    //author:   luoweifu
    //---------------------------------------------------------------
    virtual ITextUnit* AddTextUnit() = 0;
};

ITextUnit.h

#pragma once

class ITextUnit
{
public:
    ~ITextUnit(void){}

public:
    //---------------------------------------------------------------
    //function:
    //          GetId 获得ID
    //Access:
    //          virtual  public
    //Parameter:
    //Returns:
    //          int - 返回ID
    //Remarks:
    //          ...
    //author:   luoweifu
    //---------------------------------------------------------------
    virtual int GetId() = 0;

    //---------------------------------------------------------------
    //function:
    //          SetId 设置ID
    //Access:
    //          virtual  public
    //Parameter:
    //          [in] int id - 要设置的ID
    //Returns:
    //          void -
    //Remarks:
    //          ...
    //author:   luoweifu
    //---------------------------------------------------------------
    virtual void SetId(int id) = 0;

};

提供C接口

从上面的代码我们可以看到IPage可以由IDocument创建,ITextUnit可以由IPage创建。那问题来了,IDocument由谁来创建呢?这时我们可以提供两个全局的函数CreateDoc和DestroyDoc用来创建和销毁IDocument的对象指针,这两个函数是全局函数(C类型的函数),我们需要为其提供C的导出接口(这很重要)。其接口定义如下:

#pragma once

#include "IDocument.h"
#include "IPage.h"
#include "ITextUnit.h"

//===============================================================
//要导出静态库时,导出库的工程和使用库的工程都要加预编译宏EXPORT_STATIC
//要导出动态库时,导出库的工程要加预编译宏EXPORT_STATIC,使用库的工程不用
//===============================================================
#ifdef EXPORT   //导出库
#define _API_  __declspec(dllexport)
#else           //导入库
#define _API_  __declspec(dllimport)
#endif  //EXPORT

#ifdef EXPORT_STATIC    //导出静态库
#define EBAPI int
#else                   //导出动态库
#define EBAPI extern "C" _API_ int
#endif  //EXPORT_STATIC

//---------------------------------------------------------------
//function:
//      CreateDoc 创建Document对象
//Access:
//       public
//Parameter:
//      [in] IDocument * & pDocument -
//Returns:
//      EBAPI -
//Remarks:
//      ...
//author:    luowf[/luoweifu]
//---------------------------------------------------------------
EBAPI CreateDoc(IDocument*& pDocument);

//---------------------------------------------------------------
//function:
//      DestroyDoc 销毁一个Document对象
//Access:
//       public
//Parameter:
//      [in] IDocument * pDocument -
//Returns:
//      EBAPI -
//Remarks:
//      ...
//author:    luowf[/luoweifu]
//---------------------------------------------------------------
EBAPI DestroyDoc(IDocument* pDocument);

使用库

我们可以将EBook编译成一个静态库,然后再创建一个新的工程使用它。EBook工程设置:

图3: 工程配置

创建一个新的工程UseEBook使用EBook库。UseEBook工程配制:

Generation Properties\C++\Preprocess\Preprocess Definitions:EXPORT_STATIC

Generation Properties\Linker\General\Addtional Library Directories:lib库所在路径

Generation Properties\Linker\Input\Addtional Dependencies:EBook.lib

测试代码:

#include "stdafx.h"

#include <iostream>

int _tmain(int argc, _TCHAR* argv[])
{
    IDocument* pDoc = NULL;
    if(CreateDoc(pDoc) != 0)
    {
        return -1;
    }

    IPage* pPage = pDoc->AddPage();
    ITextUnit* pTextUnit = pPage->AddTextUnit();
    std::cout << pTextUnit->GetId() << std::endl;

    DestroyDoc(pDoc);

    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得用于任何商业用途,转载请注明出处。

时间: 2024-08-01 13:33:46

C++“隐藏实现,开放接口”的实现方案的相关文章

开放接口/RESTful/Api服务的设计和安全方案

总体思路 这个涉及到两个方面问题:一个是接口访问认证问题,主要解决谁可以使用接口(用户登录验证.来路验证)一个是数据数据传输安全,主要解决接口数据被监听(HTTPS安全传输.敏感内容加密.数字签名) 用户身份验证:Token与Session开放接口Api服务其实就是客户端与服务端无状态交互的一种形式,这有点类似REST(Representational State Transfer)风格.普通网站应用一般使用session进行登录用户信息的存储和验证(有状态),而开放接口服务/REST资源请求则

如何做一个简单的开放接口(2)-核心引擎(上)

1.要实现的功能 书接上回,本回书我们要完成开放接口平台核心引擎的多Handler支持机制. 如图1所示. 图1 开放接口服务器端架构 2.Filter还是装饰模式 装饰者模式貌似是一个实现的候选,类似Java的I/O实现. 多"装饰"一层,就获得了新的功能,原来的功能还在. 对我现在的应用场景来说,这种实现方式过于复杂了. 相对而言,Filter更简洁. 当前的应用场景对性能是有极高要求的,不适合使用哪怕稍微复杂的模式. 3.Handler接口定义 我的Handler接口定义如下.

[JAVA]基于微信公众平台开放接口编写的sdk

最近在研究微信公众平台提供的公众服务号,以及提供的开放接口. 写了一个相对来说比较简单的基于java的微信sdk,目前实现的功能没有覆盖所有接口. 有兴趣的话,大家可以在这个基础上进行改进和完善,这样就不用重复发明轮子了. 所有的代码已经提交到github上: https://github.com/lemonbar/wxsdk 下载代码后,按照自己申请的微信公众号信息,来修改AppInfo.java文件. App.java文件中已经写了几个例子,可以单独运行以test开头的static方法,进行

百度翻译开放接口JAVA实现

百度翻译的开放接口文档在这里:http://api.fanyi.baidu.com/api/trans/product/apidoc 至于申请key啥的就不说了,直接进实现. 我是用HC4.5.1做的,在部分代码处理上面,会跟3 4 的版本有点不一致. public static void main(String[] args) { String query = "搞个乜"; get(query); post(query); } private static void get(Stri

微博开放接口的使用

     android开发中总是会用到第三方接口登录,下面向大家分享一下项目中微博开放接口的使用方法.      首先登录官网       第一步:创建应用 第二步:下载SDK 并导入Demo  http://open.weibo.com/wiki/SDK 在代码中配置appkey 2.配置重定向网址 第三步  编辑基本信息 第四步  1.清单中拷贝权限,并配置授权Actiity页面WeibosdkBrowser 2.项目依赖weiboSDK库 注意:从weiboDemo中拷贝所有so文件到w

如何做一个简单的开放接口(4)-常见Handler的参考实现

1.概述 核心引擎搞定了,接下来的主要工作就是逐个开发 Handler 了. 常用的Handler包括授权(AuthHandler).流量控制(TrafficControlHandler).加解密(EncryptHandler).安全(SecurityHandler).压缩(ZipHandler).序列化(KryoHandler)等. 其他外围功能还包括对调用方的管理功能,开放接口介绍网站等,不再冗述. 2.常用Handler 2.1.授权 实现一个达到实用级别的授权实现需要另开一个专题来讲,这

开放接口平台 in Action(汇总目录)

如何做一个简单的开放接口(1)-功能设计 http://blog.csdn.net/stationxp/article/details/45793039 如何做一个简单的开放接口(2)-核心引擎(上) http://blog.csdn.net/stationxp/article/details/45797931 如何做一个简单的开放接口(3)-核心引擎(下) http://blog.csdn.net/stationxp/article/details/45804495 如何做一个简单的开放接口(

App开放接口api安全性—Token签名sign的设计与实现

前言 在app开放接口api的设计中,避免不了的就是安全性问题,因为大多数接口涉及到用户的个人信息以及一些敏感的数据,所以对这些 接口需要进行身份的认证,那么这就需要用户提供一些信息,比如用户名密码等,但是为了安全起见让用户暴露的明文密码次数越少越好,我们一般在web项目 中,大多数采用保存的session中,然后在存一份到cookie中,来保持用户的回话有效性.但是在app提供的开放接口中,后端服务器在用户登录后 如何去验证和维护用户的登陆有效性呢,以下是参考项目中设计的解决方案,其原理和大多

如何做一个简单的开放接口(1)-功能设计

1.缘起 最初,系统系统间都是孤立的.业务是贯穿的,系统间也必然需要交互数据. 实现数据交互的方式有好多种,可以通过ftp交互Excel文件,可以通过互相读写的中间库,可以通过Web Services. 系统间可能是点对点交互,可能是一对多广播,可能是多对一汇总,可能是多对多协同. 在复杂IT场景中,多信息系统各司其职,协作完成工作.交互数据的事情怎样做呢? 数据交互有两个核心问题要解决:一是协议,二是数据格式.这两个都需要通信双方协商. 如果是企业内部的各信息系统,可以搭建统一的数据交互平台解