什么叫接口和实现分离,如何实现

时间:2022-04-29 13:24:38
如题,什么叫做把接口和实现分离,好像说这样的话模块间的依赖会自然转化为对接口数据类型的依赖,不知道该如何理解。另外,能否给出个简单的接口和实现分离的例子,多谢。

13 个解决方案

#1


  抽象类 应该可以吧....

#2


个人认为就好比函数声明和函数实现分开

#3


公有接口是类的抽象组件,类函数定义是实现细节,把两者分离,具体做法就是类成员函数定义与公有接口分属不同的代码文件。

接口与实现的分离其实你一直在使用,最直接的例子就是标准库,平时你使用标准库的头文件,这个就是个接口,而标准库被封装在不同的地方,例如静态库,这个就是实现。两者是分离的。

#4


抽象类提供接口,实现类提供具体的借口实现
使用的时候抽象类的借口不变,具体实现由不同的实现类实现

#5


接口主要是用于模块间的交互,实现就是具体的处理逻辑;如果接口过多的牵扯处理逻辑,代码的重用性会比较差;如果接口和实现分开,新增功能只需要关注具体的实现,不需要改动接口。

#6


   我们知道,类有接口(成员函数),有数据、状态变量等,这些都有实现代码。由于接口是要向外公开的,而实现是需要隐藏的(用户不需要知道),这样才能应对变化。比如接口的实现有变化,或者一个接口有多种可能的实现,我们就可以随意修改这些实现,而不影响用户的使用,因为用户看到的只是对外公开的接口,接口并没有变。

   将接口与实现分离的技术:

   (1)Interface class:将接口部分实现为abstract base class,在C++中,这个抽象类中含一个virtual析构函数和一组pure virtual函数,实现部分则由派生出来的各个子类来完成。C++/Java/C#中都有现成的abstract类机制,例子就不需要举了。

   (2)Handle class:也称为pimpl技术,就是把隶属对象的数据(即实现)从原对象中抽离出来,封装成一个独立的impl对象,在原对象中用一个指针成员指向它,一般使用智能指针。举一个例子,按钮组件通常都有一个背景图像作为数据,通常这个图像作为组件类的一个成员,为了分离实现,我们把这些数据抽离出来进行独立的封装:

struct PMImpl{ //封装数据对象的
    std::tr1::shared_ptr<Image> bgImage; //指向背景图像的智能指针
    int imageChanges;  //背景图像更改次数
};

class Button{ //按钮类
private:
    Mutex mutex; //互斥锁
    std::tr::shared_ptr<PMImpl> pImpl; //指向数据对象的智能指针
public:
    void changeBackground(std::istream &imgSrc);
    //...
};

void Button::changeBackground(std::istream &imgSrc){
    using std::swap;  //使用这个函数进行异常安全编程
    Lock m1(&mutex); //加锁,下面成为临界区
    std::tr1::shared_ptr<PMImpl> pNew(new PMImpl(*pImpl)); //创建临时的pNew,
                                              //并指向了原有的数据对象(含有背景图像)
    pNew->gbImage.reset(new Image(imgSrc)); //根据传进来的图像,更改背景图像
    ++pNew->imageChanges;  //更改次数加1
    swap(pImpl,pNew); //把更改后的数据交换到pImpl中,并且会释放互斥锁mutex,
                      //从而完成了Button背景图像的更改
}

#7


引用 5 楼 asksgp 的回复:
接口主要是用于模块间的交互,实现就是具体的处理逻辑;如果接口过多的牵扯处理逻辑,代码的重用性会比较差;如果接口和实现分开,新增功能只需要关注具体的实现,不需要改动接口。

你的意思我大概明白了,我现在的问题是:
1.你的意思就是接口要具有可扩展性,那么这样的接口设计时要注意些什么呢,或者说和一般的函数原型有什么不同呢?是不是数据类型要设计成抽象的(可以通过typedef重定义),然后参数个数要多一些(满足可以预知的最大个数)?
2.接口和实现分离应该不是强调接口的声明和实现放在不同的文件中吧,感觉单纯的这样没啥意思吧。
最好能举个简单的例子说一下,多谢。

#8


应该讲的就是软件的设计原则:对接口编程吧

#9


就是你定义接口,你定义标准,让别人去具体实现,至于他怎么实现的,那你就不管了。

定义接口都是牛人做的事。

#10


哈哈。哈哈。。。。

/// 接口类.h

/// 实现类.cpp

#11


引用 7 楼 heronism 的回复:
引用 5 楼 asksgp 的回复:
接口主要是用于模块间的交互,实现就是具体的处理逻辑;如果接口过多的牵扯处理逻辑,代码的重用性会比较差;如果接口和实现分开,新增功能只需要关注具体的实现,不需要改动接口。

你的意思我大概明白了,我现在的问题是:
1.你的意思就是接口要具有可扩展性,那么这样的接口设计时要注意些什么呢,或者说和一般的函数原型有什么不同呢?是不是数据类型要设计成抽象的(可以通过typedef重定义),然后参数个数要多一些(满足可以预知的最大个数)?
2.接口和实现分离应该不是强调接口的声明和实现放在不同的文件中吧,感觉单纯的这样没啥意思吧。
最好能举个简单的例子说一下,多谢。


你应该去看一下《c语言接口与实现》这本书,你就知道怎么做了。

#12


这个是说面向对象的把   父类是抽象类定义接口  而实现在派生类里

#13



#include <stdio.h>
#include <stdlib.h>

struct Interface
{
void (*f)();//定义了一个接口
};


void fun1()//实现1
{
printf("fun1......\n");
}
void fun2()//实现2
{
printf("fun2......\n");
}
int main()
{
Interface a;
a.f=fun1;
a.f();
a.f=fun2;
a.f();
system("pause");
}

比较简单的例子~~~

#1


  抽象类 应该可以吧....

#2


个人认为就好比函数声明和函数实现分开

#3


公有接口是类的抽象组件,类函数定义是实现细节,把两者分离,具体做法就是类成员函数定义与公有接口分属不同的代码文件。

接口与实现的分离其实你一直在使用,最直接的例子就是标准库,平时你使用标准库的头文件,这个就是个接口,而标准库被封装在不同的地方,例如静态库,这个就是实现。两者是分离的。

#4


抽象类提供接口,实现类提供具体的借口实现
使用的时候抽象类的借口不变,具体实现由不同的实现类实现

#5


接口主要是用于模块间的交互,实现就是具体的处理逻辑;如果接口过多的牵扯处理逻辑,代码的重用性会比较差;如果接口和实现分开,新增功能只需要关注具体的实现,不需要改动接口。

#6


   我们知道,类有接口(成员函数),有数据、状态变量等,这些都有实现代码。由于接口是要向外公开的,而实现是需要隐藏的(用户不需要知道),这样才能应对变化。比如接口的实现有变化,或者一个接口有多种可能的实现,我们就可以随意修改这些实现,而不影响用户的使用,因为用户看到的只是对外公开的接口,接口并没有变。

   将接口与实现分离的技术:

   (1)Interface class:将接口部分实现为abstract base class,在C++中,这个抽象类中含一个virtual析构函数和一组pure virtual函数,实现部分则由派生出来的各个子类来完成。C++/Java/C#中都有现成的abstract类机制,例子就不需要举了。

   (2)Handle class:也称为pimpl技术,就是把隶属对象的数据(即实现)从原对象中抽离出来,封装成一个独立的impl对象,在原对象中用一个指针成员指向它,一般使用智能指针。举一个例子,按钮组件通常都有一个背景图像作为数据,通常这个图像作为组件类的一个成员,为了分离实现,我们把这些数据抽离出来进行独立的封装:

struct PMImpl{ //封装数据对象的
    std::tr1::shared_ptr<Image> bgImage; //指向背景图像的智能指针
    int imageChanges;  //背景图像更改次数
};

class Button{ //按钮类
private:
    Mutex mutex; //互斥锁
    std::tr::shared_ptr<PMImpl> pImpl; //指向数据对象的智能指针
public:
    void changeBackground(std::istream &imgSrc);
    //...
};

void Button::changeBackground(std::istream &imgSrc){
    using std::swap;  //使用这个函数进行异常安全编程
    Lock m1(&mutex); //加锁,下面成为临界区
    std::tr1::shared_ptr<PMImpl> pNew(new PMImpl(*pImpl)); //创建临时的pNew,
                                              //并指向了原有的数据对象(含有背景图像)
    pNew->gbImage.reset(new Image(imgSrc)); //根据传进来的图像,更改背景图像
    ++pNew->imageChanges;  //更改次数加1
    swap(pImpl,pNew); //把更改后的数据交换到pImpl中,并且会释放互斥锁mutex,
                      //从而完成了Button背景图像的更改
}

#7


引用 5 楼 asksgp 的回复:
接口主要是用于模块间的交互,实现就是具体的处理逻辑;如果接口过多的牵扯处理逻辑,代码的重用性会比较差;如果接口和实现分开,新增功能只需要关注具体的实现,不需要改动接口。

你的意思我大概明白了,我现在的问题是:
1.你的意思就是接口要具有可扩展性,那么这样的接口设计时要注意些什么呢,或者说和一般的函数原型有什么不同呢?是不是数据类型要设计成抽象的(可以通过typedef重定义),然后参数个数要多一些(满足可以预知的最大个数)?
2.接口和实现分离应该不是强调接口的声明和实现放在不同的文件中吧,感觉单纯的这样没啥意思吧。
最好能举个简单的例子说一下,多谢。

#8


应该讲的就是软件的设计原则:对接口编程吧

#9


就是你定义接口,你定义标准,让别人去具体实现,至于他怎么实现的,那你就不管了。

定义接口都是牛人做的事。

#10


哈哈。哈哈。。。。

/// 接口类.h

/// 实现类.cpp

#11


引用 7 楼 heronism 的回复:
引用 5 楼 asksgp 的回复:
接口主要是用于模块间的交互,实现就是具体的处理逻辑;如果接口过多的牵扯处理逻辑,代码的重用性会比较差;如果接口和实现分开,新增功能只需要关注具体的实现,不需要改动接口。

你的意思我大概明白了,我现在的问题是:
1.你的意思就是接口要具有可扩展性,那么这样的接口设计时要注意些什么呢,或者说和一般的函数原型有什么不同呢?是不是数据类型要设计成抽象的(可以通过typedef重定义),然后参数个数要多一些(满足可以预知的最大个数)?
2.接口和实现分离应该不是强调接口的声明和实现放在不同的文件中吧,感觉单纯的这样没啥意思吧。
最好能举个简单的例子说一下,多谢。


你应该去看一下《c语言接口与实现》这本书,你就知道怎么做了。

#12


这个是说面向对象的把   父类是抽象类定义接口  而实现在派生类里

#13



#include <stdio.h>
#include <stdlib.h>

struct Interface
{
void (*f)();//定义了一个接口
};


void fun1()//实现1
{
printf("fun1......\n");
}
void fun2()//实现2
{
printf("fun2......\n");
}
int main()
{
Interface a;
a.f=fun1;
a.f();
a.f=fun2;
a.f();
system("pause");
}

比较简单的例子~~~