面向接口编程
- 格式:doc
- 大小:540.50 KB
- 文档页数:29
项⽬开发过程中论“⾯向接⼝编程”的重要性刚刚领导了⼀轮新项⽬开发,在开发过程中⾄始⾄终坚持“⾯向接⼝编程”的原则,并基于此原则进⾏分⼯合作,最终较⾼质量的完成了代码编写过程。
总结项⽬过程,深味⾯向接⼝编程思想的重要性,个中滋味与君分享。
⾯向接⼝编程的好处之⼀是,可以站在全局⾓度俯瞰项⽬架构,对项⽬需求有更深层次的理解。
往常我们只归纳项⽬流程以及设计对象,但是对于接⼝的设计没有提前,算是做到哪再想有哪些接⼝,这样很有可能会在没有完全理解整体需求的情况下就开动,造成了后期调试的⿇烦和返⼯。
⾯向接⼝编程的另⼀个好处是,从横向将项⽬切割成⼀个⼀个的剖⾯,特别适合现在分层⽐较复杂且各层权责分明的项⽬架构。
各层之间的交互关⼼的其实是接⼝定义得如何,事先将接⼝确定下来,可以是项⽬⾻架趋于稳定,也可以降低开发中的风险和不可测。
⾯向接⼝编程还有⼀个好处是,使team leader能更好地把控项⽬的开发节奏。
在分⼯阶段,既可以按照功能模块和功能点分⼯,也可以按照层次之间进⾏分⼯。
例如,之前的项⽬开发中,曾经尝试过让不同⼈分别负责前端页⾯和后端服务开发,由于事先未定义好彼此间交互和通信的接⼝,并⾏开发到联调阶段发现,双⽅对于各⾃所需差异很⼤,联调耗时甚⾄⽐开发时间还长,得不偿失。
⽽事先定义好接⼝,甚⾄细化到url和接⼝的命名,参数和返回的类型,则⼤⼤缩短了联调的时间,最终联调时间仅占开发时间的五分之⼀不到,效果明显。
在单元测试阶段,由于接⼝固定,可以将各层的单元测试提前写好,节省了开发时间。
通过实际项⽬开发的实践,以及对过往项⽬开发的总结,可以深切体会到⾯向接⼝编程这种思想的好处。
接⼝者,通信协议也。
项⽬间协作和配合完全靠⼀个个清晰简约的接⼝实现。
沿着这些接⼝的脉络,能更好地提⾼团队开发效率,促进团队进步。
详解Java中的面向接口编程在Java编程中,面向接口编程是一种重要的编程思想和实践方式。
通过面向接口编程,我们可以实现代码的灵活性、可扩展性和可维护性。
本文将详细介绍Java中的面向接口编程,并探讨其优势和应用。
一、什么是接口?在Java中,接口是一种定义了一组方法的抽象类型。
接口可以看作是一种契约,规定了类应该具有的行为。
通过实现接口,类可以拥有接口定义的方法,并提供自己的实现。
在接口中,我们只定义方法的签名,而不包含具体的实现。
这使得接口成为一种非常灵活的编程工具,可以在不改变接口定义的情况下,实现不同的具体逻辑。
二、为什么要使用面向接口编程?1. 提高代码的灵活性通过面向接口编程,我们可以将程序的依赖关系从具体的实现类解耦,而是依赖于接口。
这样,当需要替换具体的实现类时,只需要修改依赖的接口即可,而不需要修改大量的代码。
这样可以提高代码的灵活性和可维护性。
2. 实现多态面向接口编程可以实现多态。
多态是指在父类或接口类型的引用变量中,可以指向不同子类或实现类的实例。
通过多态,我们可以编写通用的代码,而不需要考虑具体的实现类。
这样可以提高代码的复用性和扩展性。
3. 规范化编程接口定义了类应该具有的行为,通过面向接口编程,我们可以规范化编程。
当多个类实现同一个接口时,它们必须提供相同的方法,这样可以提高代码的一致性和可读性。
三、如何使用面向接口编程?1. 定义接口在使用面向接口编程之前,首先需要定义接口。
接口的定义使用`interface`关键字,例如:```javapublic interface Animal {void eat();void sleep();}```在上面的例子中,我们定义了一个`Animal`接口,规定了`eat()`和`sleep()`两个方法。
2. 实现接口接口只定义了方法的签名,不包含具体的实现。
因此,我们需要通过实现接口来提供具体的逻辑。
实现接口使用`implements`关键字,例如:```javapublic class Cat implements Animal {@Overridepublic void eat() {System.out.println("Cat is eating.");}@Overridepublic void sleep() {System.out.println("Cat is sleeping.");}}```在上面的例子中,我们定义了一个`Cat`类,实现了`Animal`接口,并提供了`eat()`和`sleep()`方法的具体实现。
C语⾔实现⾯向接⼝编程今天更新的⽂章,我相信是⼤伙喜欢的,来聊聊⾯向接⼝编程。
不是⼀直都吹嘘着⾯向对象编程吗?怎么今天⼜来⼀个⾯向接⼝编程,很多⼈要说我不讲武德了。
1⾯向接⼝是啥?不⽤慌,其实⾯向接⼝编程不是什么新鲜玩意,说得直⽩点就是函数指针的使⽤,不过我觉得可以形成⼀种编程的思想来指导嵌⼊式程序设计,特别是对于降低代码的耦合还是⽐较奏效的。
⾯向接⼝编程⽐⾯向对象要更⽜吗?为什么不直接玩⾯向对象编程呢?其实bug菌这么多年开发过来,真正把C完完全全⽤⾯向对象的⽅式进⾏编写是⾮常少的,像C++中的继承、多态、虚函数等等⾯向对象特性,如果均⽤C语⾔来维护和实现是⾮常复杂的,并且你还不能保证没有bug。
再说了你写了⼀堆代码让C的特性更加的像C++,那为什么不直接使⽤C++呢?难道你觉得那些特性你能⽤C写得⽐C++更好?别重复造轮⼦了。
不过,话说回来,能够在C语⾔中借鉴⼀些⾯向对象的语⾔特性和思想,确实能够让C代码更加的优雅和灵活,所以今天聊聊⾯向接⼝编程,它仅仅只是⾯向对象的⼀部分,不过在⼀般的嵌⼊式开发中使⽤性价⽐还是⽐较⾼的。
2⾯向接⼝编程话不多说,先上⼀个⾯向接⼝编程的Demo:参考demo:1#include <stdio.h>2#include <stdlib.h>34/******************************************** 5 * Note: 共⽤接⼝的定义 6 * author:bug菌7 *******************************************/8struct Interface {9 int (*Initial)(void* handle);10 int (*Send)(void* handle,char * buff,int count);11 int (*Recv)(void* handle,char * buff);12 int (*Destory)(void* handle);13};1415 /******************************************** 16 * Note: 具体类型的定义 17 * author:bug菌18 *******************************************/19typedef struct _tag_protocolType1 {20 struct Interface bi; //公共通信接⼝21 char* CommTypeName; //通信名称22 //不同通信类型的其他成员......23}protocolType1;242526/******************************************** 27 * Note:其中⼀种报⽂协议的简单接⼝实现 28 * author:bug菌29 *******************************************/30void protocol_Initial(void* handle)31{32 protocolType1* p = ( protocolType1*)handle;33 p->CommTypeName = 'protocolType1'; //可以通过公共接⼝传参访问原对象的所有成员3435 printf('%s Initial\n',p->CommTypeName);36}3738void protocol_Send(void* handle,char * buff,int count)39{40 protocolType1* p = ( protocolType1*)handle;41对于⾃动测试程序框架,接⼝的预留是⾮常重要的,可以通过虚拟接⼝来测试业务逻辑,能够模拟更多实际环境下不同的⼯况来进⾏测试。
⾯向接⼝编程的好处⾯向接⼝编程⼀些好处:1.⼀个功能的调⽤者只需要关⼼如何使⽤此功能,⽽⽆须关注功能的实现。
如:如我们在main ⽅法中调⽤⼀个client程序,我们只需要Client client = new ClientImpl(),⽆论 ClientImpl 类中定义了多么复杂的成员函数和成员变量(包括javadoc),你都看不到,你也⽆须看到。
2.⾯向接⼝编程便于团队合作,有了统⼀的接⼝(接⼝是公开的,⾥⾯的⽅法都是public的),⽆须担⼼别⼈的程序⽆法使⽤我的实现(他根本就不关⼼)。
假如我们团队正在做⼀个计算器⼩程序,想要计算1+2+...+100=?,product manager 写了⼀个接⼝,让两个员⼯分别实现,他最后看那个程序算法算得快,于是这两个员⼯就对接⼝分别做了实现。
PM只需要写⼀个程序就可以评估他们的算法。
public int getTime(Interface in){int a = System.currentTime();in.run();return Sustem.currentTime()-a;}试想⼀下,如果没有接⼝,这个经理必须分别new这两个员⼯的class,然后调⽤可能不同的⽅法(A:run(), B:go())来运⾏。
3.(回答你的问题)接⼝的继承关注的是功能的扩展,⽽不是代码的修改。
class的继承就是功能性代码的增加。
两者关注的焦点不同。
本⼈观点:我个⼈认为,接⼝⼀旦设计好了,很少需要修改,除⾮业务逻辑或需求有较⼤变动。
多继承的⽤途(只是举个例⼦):如,SUN对⼀项技术写了⼀个规范如J2EE的JMS规范,很多vender在⾃⼰的应⽤服务器(如WebSphere, WebLogic, Jboss等)都要实现这⼀个规范,故且把这个规范叫做接⼝,每个vender想要对这个规范添加⾃⼰独特的功能,怎么办呢?就是⽤接⼝的继承,然后对继承了的接⼝做实现。
举个例⼦:public interface InterfaceA {public void method1();}public interface InterfaceB {public void method2();}public interface InterfaceAB extends InterfaceA, InterfaceB{public void method3();}public class InterfaceAImpl implements InterfaceA {@Overridepublic void method1() {System.out.println("The implemention of InterfaceA.");}}public class InterfaceBImpl implements InterfaceB {@Overridepublic void method2() {System.out.println("The implemention of InterfaceB.");}}public class InterfaceABImpl implements InterfaceAB {@Overridepublic void method1() {System.out.println("The implemention of InterfaceAB(method1).");}@Overridepublic void method2() {System.out.println("The implemention of InterfaceAB(method2)."); }@Overridepublic void method3() {System.out.println("The implemention of InterfaceAB(method3)."); }}public class Main {public static void main(String[] args) {InterfaceA a = new InterfaceABImpl();InterfaceB b = new InterfaceABImpl();InterfaceAB ab = new InterfaceABImpl();a.method1();b.method2();ab.method3();}}利⽤多态(向上转型),我们就可以达到不同vender间接⼝的统⼀。
C#⾯向接⼝编程⾯向接⼝编程就是将对象中的某个功能提取出来作为接⼝,⽽功能的具体实现则交由继承⾃这个接⼝的实现类处理。
⾯向接⼝的好处是降低程序的耦合性,当有新的功能时只需要对新功能进⾏编写,不需要修改已有的代码下⾯是⼀个简单的范例:1//⽗类2public class Duck3 {4protected IFlyBehaviour flyBehaviour;5//可以动态修改对象的某⼀功能的实现6public void SetDuckFly(IFlyBehaviour fb)7 {8 flyBehaviour = fb;9 }10public void DuckFly()11 {12 flyBehaviour.Fly();13 }14 }1516//⼩鸭⼦类,继承鸭⼦类17public class LittleDuck : Duck18 {19public LittleDuck()20 {21 flyBehaviour = new SlowFly();22 }23 }2425//⼤鸭⼦类,继承鸭⼦类26public class BigDuck : Duck27 {28public BigDuck()29 {30 flyBehaviour = new QuickFly();31 }32 }3334//飞⾏为的接⼝,只定义了飞⾏的⽅法⽽未实现35public interface IFlyBehaviour36 {37void Fly();38 }3940//实现快速飞的⾏为类,继承了飞⾏接⼝41public class QuickFly : IFlyBehaviour42 {43public void Fly()44 {45 Console.WriteLine("飞⾏速度⾮常快");46 }47 }4849//实现慢速飞⾏的⾏为类,继承了飞⾏接⼝50public class SlowFly : IFlyBehaviour51 {52public void Fly()53 {54 Console.WriteLine("飞⾏速度⾮常慢");55 }56 }假设作为⽗类的鸭⼦类Duck具有飞⾏的功能,继承⾃它的两个⼦类⼤鸭⼦BigDuck飞得快,⼩鸭⼦LittleDuck飞的慢,通过⾯向接⼝的⽅式进⾏实现,⽽通过⽗类Duck中的SetDuckFly()⽅法,我们还可以在程序运⾏过程中动态的去修改某⼀功能执⾏:1 BigDuck bigDuck = new BigDuck();2 bigDuck.DuckFly();34 LittleDuck littleDuck = new LittleDuck();5 littleDuck.DuckFly();67 littleDuck.SetDuckFly(new QuickFly());8 littleDuck.DuckFly();结果:1飞⾏速度⾮常快2飞⾏速度⾮常慢3飞⾏速度⾮常快。
实验三面向接口编程一、实验目的:1.理解接口编程、面向对象编程的思想, 两者的区别, 以及各自的优缺点;2.掌握AE接口实现图层加载的方法:IworkspaceFactory-->Workspace->IfeatureWorkSpace->IFeatrueClass->IFeature();二、 3.理解并掌握使用UI进行属性查询和空间查询;实验内容:1.利用IWorkSpace接口在Map中增加一个GeoDatabase图层;2.利用Imap的SelectBy*实现简单选择;3.利用IQueryFilte.实现简单空间查询。
(未实现)三、实验心得:1.二次开发初期,深刻理解面向接口编程思想很重要。
通过实验,我觉得可以这样理解:接口并不是必须的,去掉完全可以;只不过是为了方便查找,给相似的类一个接口,通过这个接口就可以容易地找到要用的类。
接口就是一个把所有类再分成大的类的规则。
2.通过这次实验的最大收获是,理解了整个程序框架的基本架构。
一个程序主窗体/对应于一个主程序/,可以同时创建多个窗体/,并编写子程序/,主程序通过“接口调用抽象类—抽象类创建一个普通类—普通类实例化子窗体”的模式调用子程序/。
三、实验过程1.什么是接口?什么是面向接口编程?有何优点?答案:(1)接口是一组规则的集合, 它规定了实现本接口的类或接口必须拥有的一组规则;是在一定粒度视图上同类事物的抽象表示。
接口从更深层次的理解, 应是定义(规范, 约束)与实现(名实分离的原则)的分离。
接口应有两类: 第一类是对一个体的抽象, 它可对应为一个抽象体(abstract class);第二类是对一个体某一方面的抽象, 即形成一个抽象面(interface);一个体有可能有多个抽象面。
接口编程的思想: 在系统分析和架构中, 分清层次和依赖关系, 每个层次不是直接向其上层提供服务(即不是直接实例化在上层中), 而是通过定义一组接口, 仅向上层暴露其接口功能, 上层对于下层仅仅是接口依赖, 而不依赖具体类。
C语⾔实现⾯向接⼝编程⾯向接⼝编程实现公司中编程⽅式甲⽅和⼄⽅商定好接⼝,分别实现⾃⼰的功能最后对接成功,实现游戏功能代码⽰例:⾯向接⼝编程.c#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<string.h>#include<stdlib.h>#include "GameCompany.h"#include <time.h>//初始化游戏typedef void(*INIT_GAME)(void**gameHandle, char*name);//游戏战⽃typedef int(*FIGHT_GAME)(void*gameHandle, int gameLevel);//查看玩家信息typedef void(*PRINT_GAME)(void *gameHandle);//离开游戏typedef void(*CLOSE_GAME)(void *gameHandle);void playGame(INIT_GAME init, FIGHT_GAME fight, PRINT_GAME printGame, CLOSE_GAME closeGame){//初始化游戏void *gameHanel = NULL;printf("请输⼊玩家的姓名:\n");char name[64];scanf("%s",name);init(&gameHanel,name);//游戏战⽃int level = -1;while (1){getchar();system("cls");//清屏printf("请选择游戏难度:\n");printf("1.普通\n");printf("2.中等\n");printf("3.困难\n");scanf("%d", &level);getchar();int ret = fight(gameHanel, level);if (ret == 0){printf("挑战失败\n");break;}else{printf("挑战成功\n");printGame(gameHanel);}}//离开游戏closeGame(gameHanel);}int main(){//加⼊随机种⼦srand((unsigned int)time NULL);playGame(INIT_GAME_COMPANY,FIGHT_GAME_COMPANY,PRINT_GAME_COMPANY,CLOSE_GAME_COMPANY); return EXIT_SUCCESS;}GameCompany.c#include "GameCompany.h"//初始化游戏void INIT_GAME_COMPANY(void**gameHandle, char*name){struct Player*player = malloc(sizeof(struct Player));if (player == NULL){return;}//玩家进⾏初始化操作strcpy(player->name,name);player->level = 0;player->exp = 0;*gameHandle = player;}//游戏战⽃int FIGHT_GAME_COMPANY(void*gameHandle, int gameLevel){struct Player*plgyer = gameHandle;int addExp = 0;//累积的经验值switch (gameLevel){case 1://内部提供⼀个函数判断游戏是否胜利addExp=isWin(90,1);break;case 2:addExp = isWin(50, 2);break;case 3:addExp = isWin(30, 3);break;default:break;}//将获取的经验给⼈物⾝上plgyer->exp += addExp;plgyer->level = plgyer->exp / 10;if (addExp == 0){return 0;//战⽃失败}else{return 1;//战⽃胜利}}//查看玩家信息void PRINT_GAME_COMPANY(void *gameHandle){struct Player*player = gameHandle;printf("玩家 <%s>-----当前等级 <%d>------当前经验-----<%d>\n", player->name, player->level, player->exp); }//离开游戏void CLOSE_GAME_COMPANY(void *gameHandle){if (gameHandle == NULL){return;}free(gameHandle);gameHandle = NULL;}//判断游戏是否胜利参数1 胜率参数2 难度返回值胜利后的经验,乳沟返回的是0 代表战⽃失败int isWin(int winRate, int diff){int random = rand() % 100 + 1;//1~100if (random <= winRate){//表达胜利return 10 * diff;}else{//战⽃失败return 0;}}GameCompany.h#pragma once#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<string.h>#include<stdlib.h>struct Player{char name[64]; //玩家姓名int level; //玩家等级int exp; //玩家经验};//初始化游戏void INIT_GAME_COMPANY(void**gameHandle, char*name);//游戏战⽃int FIGHT_GAME_COMPANY(void*gameHandle, int gameLevel);//查看玩家信息void PRINT_GAME_COMPANY(void *gameHandle);//离开游戏void CLOSE_GAME_COMPANY(void *gameHandle);//判断游戏是否胜利参数1 胜率参数2 难度返回值胜利后的经验,乳沟返回的是0 代表战⽃失败int isWin(int winRate,int diff);。
面向接口编程详解(一)——思想基础我想,对于各位使用面向对象编程语言的程序员来说,“接口”这个名词一定不陌生,但是不知各位有没有这样的疑惑:接口有什么用途?它和抽象类有什么区别?能不能用抽象类代替接口呢?而且,作为程序员,一定经常听到“面向接口编程”这个短语,那么它是什么意思?有什么思想内涵?和面向对象编程是什么关系?本文将一一解答这些疑问。
1.面向接口编程和面向对象编程是什么关系首先,面向接口编程和面向对象编程并不是平级的,它并不是比面向对象编程更先进的一种独立的编程思想,而是附属于面向对象思想体系,属于其一部分。
或者说,它是面向对象编程体系中的思想精髓之一。
2.接口的本质接口,在表面上是由几个没有主体代码的方法定义组成的集合体,有唯一的名称,可以被类或其他接口所实现(或者也可以说继承)。
它在形式上可能是如下的样子:interface InterfaceName{void Method1();void Method2(int para1);void Method3(string para2,string para3);}那么,接口的本质是什么呢?或者说接口存在的意义是什么。
我认为可以从以下两个视角考虑:1)接口是一组规则的集合,它规定了实现本接口的类或接口必须拥有的一组规则。
体现了自然界“如果你是……则必须能……”的理念。
例如,在自然界中,人都能吃饭,即“如果你是人,则必须能吃饭”。
那么模拟到计算机程序中,就应该有一个IPerson(习惯上,接口名由“I”开头)接口,并有一个方法叫Eat(),然后我们规定,每一个表示“人”的类,必须实现IPerson接口,这就模拟了自然界“如果你是人,则必须能吃饭”这条规则。
从这里,我想各位也能看到些许面向对象思想的东西。
面向对象思想的核心之一,就是模拟真实世界,把真实世界中的事物抽象成类,整个程序靠各个类的实例互相通信、互相协作完成系统功能,这非常符合真实世界的运行状况,也是面向对象思想的精髓。
2)接口是在一定粒度视图上同类事物的抽象表示。
注意这里我强调了在一定粒度视图上,因为“同类事物”这个概念是相对的,它因为粒度视图不同而不同。
例如,在我的眼里,我是一个人,和一头猪有本质区别,我可以接受我和我同学是同类这个说法,但绝不能接受我和一头猪是同类。
但是,如果在一个动物学家眼里,我和猪应该是同类,因为我们都是动物,他可以认为“人”和“猪”都实现了IAnimal这个接口,而他在研究动物行为时,不会把我和猪分开对待,而会从“动物”这个较大的粒度上研究,但他会认为我和一棵树有本质区别。
现在换了一个遗传学家,情况又不同了,因为生物都能遗传,所以在他眼里,我不仅和猪没区别,和一只蚊子、一个细菌、一颗树、一个蘑菇乃至一个SARS病毒都没什么区别,因为他会认为我们都实现了IDescendable这个接口(注:descend vi. 遗传),即我们都是可遗传的东西,他不会分别研究我们,而会将所有生物作为同类进行研究,在他眼里没有人和病毒之分,只有可遗传的物质和不可遗传的物质。
但至少,我和一块石头还是有区别的。
可不幸的事情发生了,某日,地球上出现了一位伟大的人,他叫列宁,他在熟读马克思、恩格斯的辩证唯物主义思想巨著后,颇有心得,于是他下了一个著名的定义:所谓物质,就是能被意识所反映的客观实在。
至此,我和一块石头、一丝空气、一条成语和传输手机信号的电磁场已经没什么区别了,因为在列宁的眼里,我们都是可以被意识所反映的客观实在。
如果列宁是一名程序员,他会这么说:所谓物质,就是所有同时实现了“IRe flectabe”和“IEsse”两个接口的类所生成的实例。
(注:reflect v. 反映 esse n. 客观实在)也许你会觉得我上面的例子像在瞎掰,但是,这正是接口得以存在的意义。
面向对事物不加区别的对待而统一处理。
而之所以敢这样做,就是因为有接口的存在。
像那个遗传学家,他明白所有生物都实现了IDescendable接口,那只要是生物,一定有Descend()这个方法,于是他就可以统一研究,而不至于分别研究每一种生物而最终累死。
可能这里还不能给你一个关于接口本质和作用的直观印象。
那么在后文的例子和对几个设计模式的解析中,你将会更直观体验到接口的内涵。
3.面向接口编程综述通过上文,我想大家对接口和接口的思想内涵有了一个了解,那么什么是面向接口编程呢?我个人的定义是:在系统分析和架构中,分清层次和依赖关系,每个层次不是直接向其上层提供服务(即不是直接实例化在上层中),而是通过定义一组接口,仅向上层暴露其接口功能,上层对于下层仅仅是接口依赖,而不依赖具体类。
这样做的好处是显而易见的,首先对系统灵活性大有好处。
当下层需要改变时,只要接口及接口功能不变,则上层不用做任何修改。
甚至可以在不改动上层代码时将下层整个替换掉,就像我们将一个WD的60G硬盘换成一个希捷的160G的硬盘,计算机其他地方不用做任何改动,而是把原硬盘拔下来、新硬盘插上就行了,因为计算机其他部分不依赖具体硬盘,而只依赖一个IDE接口,只要硬盘实现了这个接口,就可以替换上去。
从这里看,程序中的接口和现实中的接口极为相似,所以我一直认为,接口(interface)这个词用的真是神似!使用接口的另一个好处就是不同部件或层次的开发人员可以并行开工,就像造硬盘的不用等造CPU的,也不用等造显示器的,只要接口一致,设计合理,完全可以并行进行开发,从而提高效率。
本篇文章先到这里。
最后我想再啰嗦一句:面向对象的精髓是模拟现实,这也可以说是我这篇文章的灵魂。
所以,多从现实中思考面向对象的东西,对提高系统分析设计能力大有脾益。
下篇文章,我将用一个实例来展示接口编程的基本方法。
而第三篇,我将解析经典设计模式中的一些面向接口编程思想,并解析一下.NET分对本文的补充:仔细看了各位的回复,非常高兴能和大家一起讨论技术问题。
感谢给出肯定的朋友,也要感谢提出意见和质疑的朋友,这促使我更深入思考一些东西,希望能借此进步。
在这里我想补充一些东西,以讨论一些回复中比较集中的问题。
1.关于“面向接口编程”中的“接口”与具体面向对象语言中“接口”两个词看到有朋友提出“面向接口编程”中的“接口”二字应该比单纯编程语言中的inte rface范围更大。
我经过思考,觉得很有道理。
这里我写的确实不太合理。
我想,面向对象语言中的“接口”是指具体的一种代码结构,例如C#中用interface关键字定义的接口。
而“面向接口编程”中的“接口”可以说是一种从软件架构的角度、从一个更抽象的层面上指那种用于隐藏具体底层类和实现多态性的结构部件。
从这个意义上说,如果定义一个抽象类,并且目的是为了实现多态,那么我认为把这个抽象类也称为“接口”是合理的。
但是用抽象类实现多态合理不合理?在下面第二条讨论。
概括来说,我觉得两个“接口”的概念既相互区别又相互联系。
“面向接口编程”中的接口是一种思想层面的用于实现多态性、提高软件灵活性和可维护性的架构部件,而具体语言中的“接口”是将这种思想中的部件具体实施到代码里的手段。
2.关于抽象类与接口看到回复中这是讨论的比较激烈的一个问题。
很抱歉我考虑不周没有在文章中讨论这个问题。
我个人对这个问题的理解如下:如果单从具体代码来看,对这两个概念很容易模糊,甚至觉得接口就是多余的,因为单从具体功能来看,除多重继承外(C#,Java中),抽象类似乎完全能取代接口。
但是,难道接口的存在是为了实现多重继承?当然不是。
我认为,抽象类和接口的区别在于使用动机。
使用抽象类是为了代码的复用,而使用接口的动机是为了实现多态性。
所以,如果你在为某个地方该使用接口还是抽象类而犹豫不决时,那么可以想想你的动机是什么。
看到有朋友对IPerson这个接口的质疑,我个人的理解是,IPerson这个接口该不该Women和Man,都继承Perso n,而且Women和Man绝大多数方法都相同,只有一个方法DoSomethingInWC()不同(例子比较粗俗,各位见谅),那么当然定义一个AbstractPerson抽象类比较合理,因为它可以把其他所有方法都包含进去,子类只定义DoSomethingInWC(),大大减少了重复代码量。
但是,如果我们程序中的Women和Man两个类基本没有共同代码,而且有一个Pers onHandle类需要实例化他们,并且不希望知道他们是男是女,而只需把他们当作人看待,并实现多态,那么定义成接口就有必要了。
总而言之,接口与抽象类的区别主要在于使用的动机,而不在于其本身。
而一个东西该定义成抽象类还是接口,要根据具体环境的上下文决定。
再者,我认为接口和抽象类的另一个区别在于,抽象类和它的子类之间应该是一般和特殊的关系,而接口仅仅是它的子类应该实现的一组规则。
(当然,有时也可能存在一般与特殊的关系,但我们使用接口的目的不在这里)如,交通工具定义成抽象类,汽车、飞机、轮船定义成子类,是可以接受的,因为汽车、飞机、轮船都是一种特殊的交通工具。
再譬如Icomparable接口,它只是说,实现这个接口的类必须要可以进行比较,这是一条规则。
如果Car这个类实现了Icomparable,只是说,我们的Car中有一个方法可以对两个Car的实例进行比较,可能是比哪辆车更贵,也可能比哪辆车更大,这都无所谓,但我们不能说“汽车是一种特殊的可以比较”,这在文法上都不通。
面向接口编程详解(二)——编程实例问题的提出定义:现在我们要开发一个应用,模拟移动存储设备的读写,即计算机与U盘、M P3、移动硬盘等设备进行数据交换。
上下文(环境):已知要实现U盘、MP3播放器、移动硬盘三种移动存储设备,要求计算机能同这三种设备进行数据交换,并且以后可能会有新的第三方的移动存储设备,所以计算机必须有扩展性,能与目前未知而以后可能会出现的存储设备进行数据交换。
各个存储设备间读、写的实现方法不同,U盘和移动硬盘只有这两个方法,MP3Play er还有一个PlayMusic方法。
名词定义:数据交换={读,写}看到上面的问题,我想各位脑子中一定有了不少想法,这是个很好解决的问题,很多方案都能达到效果。
下面,我列举几个典型的方案。
解决方案列举方案一:分别定义FlashDisk、MP3Player、MobileHardDisk三个类,实现各自的R ead和Write方法。
然后在Computer类中实例化上述三个类,为每个类分别写读、写方法。
例如,为FlashDisk写ReadFromFlashDisk、WriteToFlashDisk两个方法。
总共六个方法。
方案二:定义抽象类MobileStorage,在里面写虚方法Read和Write,三个存储设备继承此抽象类,并重写Read和Write方法。