`
静妙仙人
  • 浏览: 85937 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

一篇非常经典的文章(面向接口编程)

阅读更多
      首先要清楚什么是接口。接口就是标准。生活中有很多接口。如水龙头水管接口、电源接口等。现在有很多的水龙头生产商,在采用接口之前,厂商要同时提供水龙头和下水管,它们是一体的,不能变更。同时也只适用于他的这一种产品。而有了接口之后,厂商就就不用去管它的下水管如何设计了,只用安装接口标准来生产水龙头,完成后直接接到下水管上就可以了。这就是面向接口。这样的话你的下水管就可以使用所有的符合下水管标准的水龙头,而不是之前的一种水龙头。而且更换水龙头更加的方便。

放在程序中说就是。如果一个类不能确定它最后的类型,就是说不知道它以后要被实现成什么样,就可以采用面向接口的编程。所有需要这个类的地方都设成一个接口,而让这个类继承这个接口。后期要更改的时候只用继承这个接口就可以了。-----------------------------------------------------------------------------------------------------------------------------------

      面向对象设计里有一点大家已基本形成共识,就是面向接口编程,我想大多数人对这个是没有什么觉得需要怀疑的。

问题是在实际的项目开发中我们是怎么体现的呢?难道就是每一个实现都提供一个接口就了事了?反过来说,你有时候有没有觉得接口是多余的事?又或者,你仅仅是觉得现在类似spring这样的框架已习惯用接口这种方式而心存当然。

设计模式解析里提到了面向对象设计考虑的几个视角,一个是概念层,一个是规约层,一个是实现层。我如果没有猜错的话,实际上我们大多数人的眼睛一直是盯着实现层的,而这正是面向对象设计所极力避免的,即你不要在一开始就关注这些细节,你要关注的是规约(接口)。

对于实际项目开发来说,如果我们把实现的过程分为多个阶段的话我们不妨这么划分,第一阶段,根据client端的需要去设计我们的规约(interface),在这个阶段任何实现都没有,所有的任务就是定义接口所需要的职责,以及所需要的一些po,vo;第二阶段,实现前面定义的规约。

以前我是怎么做的呢?我是交叉作的,即假模假样的定义一个接口(其实我心里在想这个东西有屁用),然后定义了一个方法,然后就立即去实现这个方法,再然后我又定义一个方法,继续去实现,我现在终于想通了,这样好累,效率很低,最重要的是,这不属于真正的设计。

现在我是怎么做的呢?比如一个list.jsp里需要查询,列表,然后看明细信息,然后增加信息,我会第一步在接口里定义完(这个过程会有整体设计的意识),毫不关心底层实现(数据库、事务),我的目标就是"我想要这个功能,我想要那个功能",至于那个功能怎么实现在第一阶段我认为那不是我的事情(尽管这个事情最终还是由我来做) .大家看这个过程和前面的过程有什么本质的不同呢?就是分层的概念更加明显,你的工作更有层次,每次都有先设计再实现的步骤,而前面那个过程很容易就让你不知不觉地陷入纯实现的陷阱中。-----------------------------------------------------------------------------------------------------------------------------------

什么叫面向接口编程

在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的对系统设计人员来讲就不那么重要了;而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程我想就是指按照这种思想来编程吧!实际上,在日常工作中,你已经按照接口编程了,只不过如果你没有这方面的意识,那么你只是在被动的实现这一思想;表现在频繁的抱怨别人改的代码影响了你(接口没有设计到),表现在某个模块的改动引起其他模块的大规模调整(模块接口没有很好的设计)等等。

  Booch先生那天谈到Interaction Designer,它就是指做这类设计的人,只不过层次更高一些。我想目前我们的软件设计队伍中,这类人是最缺乏的人才之一。非接口编程?是不是就是面向过程的编程思想?

  1.关于接口的理解。

接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。

我们在一般实现一个系统的时候,通常是将定义与实现合为一体,不加分离的,我认为最为理解的系统设计规范应是所有的定义与实现分离,尽管这可能对系统中的某些情况有点繁烦。

接口的本身反映了系统设计人员对系统的抽象理解。

接口应有两类:

第一类是对一个体的抽象,它可对应为一个抽象体(abstract class)

第二类是对一个体某一方面的抽象,即形成一个抽象面(interface);

一个体有可能有多个抽象面。

抽象体与抽象面是有区别的。

2.设计接口的另一个不可忽视的因素是接口所处的环境(context,environment),系统论的观点:环境是系统要素所处的空间与外部影响因素的总和。任何接口都是在一定的环境中产生的。因此环境的定义及环境的变化对接口的影响是不容忽视的,脱离原先的环境,所有的接口将失去原有的意义。

3.按照组件的开发模型(3C),它们三者相辅相成,各司一面,浑然一体,缺一不可。

面向对象是指,我们考虑问题时,以对象为单位,考虑它的属性及方法

面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现

接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题

我认为:UML里面所说的interface是协议的另一种说法。并不是指cominterfaceCORBAinterfaceJavainterfaceDelphiinterface,人机界面的interfaceNICinterface

在具体实现中,是可以把UMLinterface实现为语言的interface,分布式对象环境的interface或其它什么interface,但就理解UMLinterface而言,指的是系统每部分的实现和实现之间,通过interface所确定的协议来共同工作。

所以我认为,面向interface编程,原意是指面向抽象协议编程,实现者在实现时要严格按协议来办。也就是BillJoy同志说的,一边翻rfc,一边写代码的意思。面向对象编程是指面向抽象和具象。抽象和具象是矛盾的统一体,不可能只有抽象没有具象。一般懂得抽象的人都明白这个道理。但有的人只知具象却不知抽象为何物。

所以只有interface没有实现,或只有实现而没有interface者是没有用的,反OO的。

所以还是老老实实面向对象编程,面向协议编程,或者什么都不面向,老老实实编程。

但是我很讨厌讨论这样的术语,不如我们谈谈什么叫面向领导的编程?面向用户的编程?领导和用户有时都很BT,我们就面向BT编程?

选择Java接口还是抽象类

很多人有过这样的疑问:为什么有的地方必须使用接口而不是抽象类,而在另一些地方,又必须使用抽象类而不是接口呢?或者说,在考虑Java类的一般化问题时,很多人会在接口和抽象类之间犹豫不决,甚至随便选择一种。

  实际上接口和抽象类的选择不是随心所欲的。要理解接口和抽象类的选择原则,有两个概念很重要:对象的行为和对象的实现。如果一个实体可以有多种实现方式,则在设计实体行为的描述方式时,应当达到这样一个目标:在使用实体的时候,无需详细了解实体行为的实现方式。也就是说,要把对象的行为和对象的实现分离开来。既然Java的接口和抽象类都可以定义不提供具体实现的方法,在分离对象的行为和对象的实现时,到底应该使用接口还是使用抽象类呢?

通过抽象类建立行为模型

在接口和抽象类的选择上,必须遵守这样一个原则:行为模型应该总是通过接口而不是抽象类定义。为了说明其原因,下面试着通过抽象类建立行为模型,看看会出现什么问题。

假设要为销售部门设计一个软件,这个软件包含一个发动机Motor)实体。显然无法在发动机对象中详细地描述发动机的方方面面,只能描述某些对当前软件来说重要的特征。至于发动机的哪些特征是重要的,则要与用户(销售部门)交流才能确定。

销售部门的人要求每一个发动机都有一个称为马力的参数。对于他们来说,这是惟一值得关心的参数。基于这一判断,可以把发动机的行为定义为以下行为。

行为1:查询发动机的马力,发动机将返回一个表示马力的整数。

虽然现在还不清楚发动机如何取得马力这个参数,但可以肯定发动机一定支持这个行为,而且这是所有发动机惟一值得关注的行为特征。这个行为特征既可以用接口定义,也可以用抽象类定义。为了说明用抽象类定义可能出现的问题,下面用抽象类建立发动机的行为模型,并用Java方法描述行为1,代码如下:

代码

public abstract Motor{ 

abstract public int getHorsepower();           

     }

Motor抽象类的基础上构造出多种具体实现,例如A型发动机、B型发动机等,再加上系统的其它部分,最后得到1.0版的软件并交付使用。一段时间过去了,现在要设计2.0版的软件。在评估2.0版软件需求的过程中,发现一小部分发动机是电池驱动的,而电池需要一定的充电时间。销售部门的人希望能够通过计算机查阅充电时间。根据这一要求定义一个新的行为,如图1所示。

行为2:查询电驱动发动机的充电时间,发动机将返回一个表示充电时间的整数。

Java方法来描述这个行为,代码如下:

代码

public abstract BatteryPoweredMotor extends Motor{     

abstract public int getTimeToRecharge();            

  }  

在销售部门的软件中,电驱动发动机也以类的形式实现,但这些类从BatteryPoweredMotor而不是Motor派生。这些改动加入到2.0版软件之后,销售部门很满意。随着业务的不断发展,不久之后光驱动的发动机出现了。销售部门要求光驱动发动机需要一定光能才能运转,光能以流明(Lumen)度量。这个信息对客户很重要,因为下雨或多云的天气里,某些光驱动发动机可能无法运转。销售部门要求为软件增加对光驱动发动机的支持,所以要定义一个新的行为。

行为3:查询光驱动发动机能够正常运转所需要的最小流明数,发动机返回一个整数。

再定义一个抽象类并把行为3转换成Java方法,代码如下:

代码

public abstract SolarPoweredMotor extends Motor{            

abstract public int getLumensToOperate();            

       }

如图1所示,SolarPoweredMotorBatteryPoweredMotor都从Motor抽象类派生。在整个软件中,90%以上的代码以相同的方式对待所有的发动机。偶尔需要检查一下发动机是光驱动还是电驱动,使用instanceof实现,代码如下:

代码

if (instanceof SolarPoweredMotor){...}            

 if (instanceof BatteryPoweredMotor){...}

无论是哪种发动机,马力这个参数都很重要,所以在所有派生的抽象类(SolarPoweredMotorBatteryPoweredMotor)中,getHorsepower()方法都有效。

现在销售部门又有了一种新的发动机,它是一种既有电驱动又有光驱动的双重驱动发动机。光驱动和电驱动的行为本身没有变化,但新的发动机同时支持两种行为。在考虑如何定义新型的光电驱动发动机时,接口和抽象类的差别开始显示出来了。新的目标是在增加新型发动机的前提下尽量少改动代码。因为与光驱动发动机、电驱动发动机有关的代码已经过全面的测试,不存在已知的Bug。为了增加光电驱动发动机,要定义一个新的SolarBatteryPowered抽象类。如果让SolarBatteryPoweredMotor抽象类派生,SolarBatteryPowered将不支持针对光驱动发动机和电驱动发动机的instanceof操作。也就是说,如果查询一个光电驱动的发动机是光驱动的,还是电驱动的,得到的答案是:都不是。

如果让SolarBatteryPoweredSolarPoweredMotor(或BatteryPoweredMotor)抽象类派生,类似的问题也会出现,SolarBatteryPowered将不支持针对BatteryPoweredMotor(或SolarPoweredMotor)的instanceof操作。从行为上看,光电驱动的发动机必须同时从两个抽象类派生,但Java语言不允许多重继承。之所以会出现这个问题,根本的原因在于使用抽象类不仅意味着定义特定的行为,而且意味着定义实现的模式。也就是说,应该定义一个发动机如何获得行为的模型,而不仅仅是声明发动机具有某一个行为。

通过接口建立行为模型

如果用接口来建立行为模型,就可以避免隐含地规定实现模式。例如,前面的几个行为改用接口定义如下。

行为1

代码

public interface Motor(){            
           public int getHorsepower();            
         }

行为2

代码            
public interface BatteryPoweredMotor extends Motor(){            
     public int getTimeToRecharge();            
}

行为3

代码          
public interface SolarPoweredMotor extends Motor{            
     abstract public int getLumensToOperate();            
}

现在光电驱动的发动机可以描述为:

代码            
public DualPoweredMotor implements SolarPoweredMotor, BatteryPoweredMotor{}        

  DualPoweredMotor只继承行为定义,而不是行为的实现模式,如图2所示。

  在使用接口的同时仍旧可以使用抽象类,不过这时抽象类的作用是实现行为,而不是定义行为。只要实现行为的类遵从接口定义,即使它改变了父抽象类,也不用改变其它代码与之交互的方式。特别是对于公用的实现代码,抽象类有它的优点。抽象类能够保证实现的层次关系,避免代码重复。然而,即使在使用抽象类的场合,也不要忽视通过接口定义行为模型的原则。从实践的角度来看,如果依赖于抽象类来定义行为,往往导致过于复杂的继承关系,而通过接口定义行为能够更有效地分离行为与实现,为代码的维护和修改带来方便。

Java接口特性学习
Java中看到接口,第一个想到的可能就是C++中的多重继承和Java中的另外一个关键字abstract。从另外一个角度实现多重继承是接口的功能之一,接口的存在可以使Java中的对象可以向上转型为多个基类型,并且和抽象类一样可以防止他人创建该类的对象,因为接口不允许创建对象。

interface关键字用来声明一个接口,它可以产生一个完全抽象的类,并且不提供任何具体实现。interface的特性整理如下:

1. 接口中的方法可以有参数列表和返回类型,但不能有任何方法体。

2. 接口中可以包含字段,但是会被隐式的声明为staticfinal

3. 接口中的字段只是被存储在该接口的静态存储区域内,而不属于该接口。

4. 接口中的方法可以被声明为public或不声明,但结果都会按照public类型处理。

5. 当实现一个接口时,需要将被定义的方法声明为public类型的,否则为默认访问类型,Java编译器不允许这种情况。

6. 如果没有实现接口中所有方法,那么创建的仍然是一个接口。

7. 扩展一个接口来生成新的接口应使用关键字extends,实现一个接口使用implements
interface
在某些地方和abstract有相似的地方,但是采用哪种方式来声明类主要参照以下两点:

1. 如果要创建不带任何方法定义和成员变量的基类,那么就应该选择接口而不是抽象类。

2. 如果知道某个类应该是基类,那么第一个选择的应该是让它成为一个接口,只有在必须要有方法定义和成员变量的时候,才应该选择抽象类。因为抽象类中允许存在一个或多个被具体实现的方法,只要方法没有被全部实现该类就仍是抽象类。

以上就是接口的基本特性和应用的领域,但是接口绝不仅仅如此,在Java语法结构中,接口可以被嵌套,既可以被某个类嵌套,也可以被接口嵌套。这在实际开发中可能应用的不多,但也是它的特性之一。需要注意的是,在实现某个接口时,并不需要实现嵌套在其内部的任何接口,而且,private接口不能在定义它的类之外被实现。

 

 

1
1
分享到:
评论

相关推荐

    Perl的面向对象编程

    本篇文章将深入探讨Perl中的面向对象编程概念、核心特性以及如何在实践中应用。 一、Perl的类与对象 在Perl中,类是通过定义一个包含数据结构(变量)和操作这些数据结构的方法(子程序)的代码块创建的。类的定义...

    Python 3面向对象编程

    本篇文章将深入探讨Python 3中的面向对象编程关键概念。 1. 类与对象 类是面向对象编程的基础,它是创建对象的蓝图或模板。在Python中,我们使用`class`关键字定义一个类。例如: ```python class Dog: def __init...

    Objective-C面向对象编程的基本应用

    本篇文章将深入探讨Objective-C面向对象编程的基本应用,以及如何通过源码和工具进行实践。 面向对象编程(Object-Oriented Programming,OOP)是现代软件开发中的核心概念,它将程序设计为一系列相互协作的对象。...

    面向对象编程-选择题.pdf

    本篇文章将根据给定的“面向对象编程-选择题.pdf”文档中的题目进行分析与总结,帮助读者更好地理解面向对象编程的基本概念及其应用。 ### 面向对象编程基础知识 1. **对象**:对象是面向对象编程的基本单位,它...

    JAVA面向对象编程_孙卫琴

    根据提供的标题、描述和标签,我们可以确定这是一篇关于Java面向对象编程的文章。虽然部分内容未能提供实际的文字描述,但从标题和描述中可以提取到的关键信息是“JAVA面向对象编程”和作者“孙卫琴”。接下来,我们...

    c++文章经典文章集合

    每篇文章可能都从不同的角度深入讲解了C++的一个方面,帮助读者理解并掌握这一复杂而强大的语言。通过阅读这些文章,无论是初学者还是经验丰富的开发者,都能从中受益,深化对C++的理解,提升自己的编程技能。

    面向对象编程基础

    本篇文章将基于提供的信息,深入探讨面向对象编程的基础知识,并通过一个生动的例子——“动物运动会”来解释这些概念。 #### 类与实例 - **类**:类是对象的模板或蓝图,它定义了对象的属性(数据成员)和行为...

    Delphi面向对象编程思想

    本篇文章将深入探讨Delphi中的面向对象编程思想。 首先,我们来理解一下对象的概念。在Delphi中,对象是类的实例,类则定义了一组相关属性(数据成员)和行为(方法)。对象可以看作是现实世界中某个实体在程序中的...

    Thrust:一个面向效率的CUDA编程库

    CUDA编程是GPU计算的核心技术,...通过这篇文章的学习,我们了解到Thrust库的许多重要特点和用法。这为开发者在使用CUDA进行编程时提供了宝贵的帮助,大大简化了并行计算的复杂性,并提高了程序的开发效率和运行效率。

    面向对象 面向对象 面向对象

    在本篇文章中,我们将深入探讨面向对象的原理、特征以及其在实际开发中的应用。 1. **对象和类**:在面向对象编程中,对象是程序的基本单元,它包含了数据(属性)和操作数据的方法(行为)。类是对具有相同属性和...

    PHP5面向对象编程

    本篇文章将详细探讨PHP5中的面向对象编程相关知识点。 一、类与对象 1. 类:类是面向对象编程的基础,它是创建对象的模板。在PHP5中,我们使用`class`关键字定义一个类,例如: ```php class MyClass { // 属性 ...

    Visual Basic与Matlab的几种接口编程技术.zip

    本篇文章将详细介绍Visual Basic与Matlab的几种接口编程技术。 1. **ActiveX Data Objects (ADO)** ADO是Microsoft提供的一种数据访问接口,允许VB程序通过MATLAB Engine API调用Matlab函数。首先,需要安装MATLAB...

    面向对象设计原则英文文章

    这篇文章将深入探讨面向对象设计原则,并结合设计模式进行讨论,帮助读者理解和应用这些原则。 首先,我们来了解四个基础的面向对象设计原则:单一职责原则(SRP)、开放封闭原则(OCP)、里氏替换原则(LSP)和...

    Python面向对象编程基础解析(二)

    上一篇文章我们已经介绍了部分Python面向对象编程基础的知识,大家可以参阅:Python面向对象编程基础解析(一),接下来,我们看看另一篇。 封装 1.为什么要封装? 封装就是要把数据属性和方法的具体实现细节隐藏...

    俄罗斯方块面向对象版

    本篇文章将深入探讨如何使用面向对象的设计模式,如工厂模式、多态和单例类等,来实现一个面向对象版的“俄罗斯方块”。 首先,我们要理解面向对象编程的核心概念。面向对象编程强调通过创建对象来表示现实世界中的...

    关于抽象类和接口的两篇不错文章

    ### 关于抽象类和接口的两篇不错文章 #### 一、理解抽象类与接口的基础概念 在面向对象编程中,抽象类与接口是两个重要的概念,它们在Java语言中有着特殊的实现方式。抽象类(Abstract Class)和接口(Interface)...

    c#一百多篇技术文章

    在C#编程语言的世界里,这“c#一百多篇技术文章”无疑是一个宝贵的资源库...每一篇文章都是深入理解C#和提升编程技巧的宝贵机会。通过深入学习并实践这些文章中的知识,开发者能够更好地驾驭C#,在项目开发中游刃有余。

    20070511am--.NET Windows编程系列课程(2):C#语法和面向对象编程

    本篇文章将根据给定的文件信息深入探讨C#语法及面向对象编程的关键概念,旨在为读者提供一份详尽的学习指南。 #### 一、数组 数组是C#中最基本的数据结构之一,用于存储相同类型的数据集合。数组中的每个元素都...

    prj门禁系统 体现高级语言编程的面向对象思想

    本篇文章将围绕"prj门禁系统"源码,深入探讨其在实现过程中体现的面向对象思想,并阐述这种编程范式的优点和核心概念。 面向对象编程是现代软件开发中的主流方法论,它基于类和对象的概念,强调数据和操作数据的...

    C#编程文章集Txt格式

    《C#编程文章集Txt格式》是一份专为C#开发者准备的学习资源,包含了多篇以Txt格式存储的编程文章。这些文章旨在帮助读者深入理解C#编程语言,提升编程技能,同时也提供了一些实用的代码示例。Txt格式的选择使得这些...

Global site tag (gtag.js) - Google Analytics