桥接模式(别名Handle/Body)、与接口、抽象接口

一、背景

在C++中封装的概念是把一个对象的外观接口同实际工作方式(实现)分离开来,但是C++的封装是不完全的,编译器必须知道一个对象的所有部分的声明,以便创建和管理它。我们可以想象一种只需声明一个对象的公共接口部分的编程语言,而将私有的实现部分隐藏起来。C + +在编译期间要尽可能多地做静态类型检查。这意味着尽早捕获错误,也意味着程序具有更高的效率。然而这对私有的实现部分来说带来两个影响:

  1. 是即使程序员不能轻易地访问实现部分,但他可以看到它;
  2. 是造成一些不必要的重复编译。

然而C++并没有将这个原则应用到二进制层次上,这是因为C++的类既是描述了一个接口同时也描述了实现的过程,示例如下:

class CMyString
    {
    private:
        const int m_cch;
        char *m_psz;
    public:
        CMyString(const char *psz);
        ~CMyString();
        int Length() const;
        int Index(const char *psz) const;
    }

CMyStirng对外过多的暴露了内存布局实现的细节,这些信息过度的依赖于这些成员变量的大小和顺序,从而导致了客户过度依赖于可执行代码之间的二进制耦合关系,这样的接口不利于跨语言跨平台的软件开发和移植。

二、桥接模式(Handle-Body模式)

解决这个问题的技术叫句柄类( handle classes)。有关实现的任何东西都消失了,只剩一个单一的指针“m_pThis”。该指针指向一个结构,该结构的定义与其所有的成员函数的定义一样出现在实现文件中。这样,只要接口部分不改变,头文件就不需变动。而实现部分可以按需要任意更动,完成后只要对实现文件进行重新编译,然后再连接到项目中

1.简单例子

这里有这项技术的简单例子。头文件中只包含公共的接口和一个简单的没有完全指定的类指针。

class CMyStringHandle
    {
    private:
        class CMyString;
        CMyString *m_pThis;
    public:
        CMyStringHandle (const char *psz);
        ~ CMyStringHandle ();
        int Length() const;
        int Index(const char *psz) const;
    };
    CMyStringHandle:: CMyStringHandle(const char *psz)
    :m_pThis(new CMyString(psz));
    {
    }
    CMyStringHandle::~ CMyStringHandle()
    {
         delete m_pThis;
    }
    int CMyStringHandle::Length()
    {
        return m_pThis->Length();
    }
    int CMyStringHandle::Index(const char *psz)
    {
     return m_pThis->Index(psz);
    }

这是所有客户程序员都能看到的。这行

class CMyString;

是一个没有完全指定的类型说明或类声明(一个类的定义包含类的主体)。它告诉编译器,CMyString是一个结构的名字,但没有提供有关该结构的任何东西。这对产生一个指向结构的指针来说已经足够了。但我们在提供一个结构的主体部分之前不能创建一个对象。在这种技术里,包含具体实现的结构主体被隐藏在实现文件中。
在设计模式中,这种思想就叫做桥接模式,别名Handle-Body 模式。

这个简单例子的Handle-Body 模式有自己的弱点:

  1. 接口类必须把每一个方法调用显示的传递给实现类,这在一个只有一个构造和一个析构的类来说显然不构成负担,但是如果一个庞大的类库,它有上百上千个方法时候,光是编写这些方法传递就有可能非常冗长,这也增加了出错的可能性。
  2. 对于关注于性能的应用每一个方法都得有两层的函数调用,嵌套的开销也不理想
  3. 由于句柄的存在依然存在编译连接器兼容性问题。

2. 接口和实现分离的Handle-Body。

使用了“接口与实现的分离”技术的 Handle-Body 解决了编译器/链接器的大部分问题,而C++面向对象编程中的抽象接口同样是运用了“接口与实现分离”的思想,而采用抽象接口对于解决这
类问题是一个极其完美的解决方案。
(1)、抽象接口的语言描述:

class IMyString
    {
        virtual int Length() const = 0;  //这表示是一个纯虚函数,具有纯虚函数的接口
        virtual int Index(const char *psz) const = 0;
    };

(2)、抽象接口的实现代码:

//接口:
class IMyString
{
            virtual int Length() const = 0;  //这表示是一个纯虚函数,具有纯虚                              //函数的接口
            virtual int Index(const char *psz) const = 0;
};

         //实现:
class CMyString:public IMyString
    {
    private:
        const int m_cch;
        char *m_psz;
    public:
        CMyString(const char *psz);
        virtual ~CMyString();
        int Length() const;
        int Index(const char *psz) const;
    }

从上面采用抽象接口的实例来看,抽象接口解决了Handle-Body所遗留下来的全部缺陷。

(3)、类层次结构图:
这里写图片描述

【转自:http://www.cnblogs.com/chessyoung/archive/2011/08/21/2147720.html,有改动】

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值