谈架构中接口的定义

不知道有没有朋友在项目一开始设计的时候会有一种迷茫感,不知道从何处下手,也许大家都知道好的设计需要先定义接口,往往是从一个很高的层次上去审视一套系统,这种做法我并不反对,但是我感觉这样做似乎需要很高的水平,很多设计者在定义完自己的接口以后都会有一种定义了和没有定义感觉一样,还不如直接写类来的实在呢,为什么会这样呢?原因很简单,缺乏设计经验,自己虽然站在很高的层次去思考,但是细节往往忽略了很多,甚至压根就没有考虑过细节,所以定义出来的接口要不就是太过抽象以至于实现的时候不容易实现,和EJB的设计初衷犯了同一种错误,也许压根就没有抽象,这样就和没有定义接口一样,不能够很清楚的定义系统的边界,在以后的开发中常常会对现有的设计进行修改,这样就破坏了原来的设计初衷,形成一种恶性循环,说了一堆废话只是为了总结一下一般的情况和找到问题的关键点。下面我来说一下我对项目初期设计的一些方法,抛砖引玉,希望更多的人能够分享一下自己的经验,同时希望能够分享一下自己在实际当中是如何去做的。
我认为软件设计其实不能离开细节,但是也不能过多的去深究细节,那么我说的细节到底细到何种程度呢?我自己的做法是细到类的方法上,开始在设计接口的时候不要过于从高端去设计,这样容易忽略很多细节,太理想化了,等到实现的时候会有很多不合适的地方,也许有人会考虑可以使用适配器模式去改变接口啊,这确实是一种方法,但是有的亡羊补牢的意思,一般只有开始没有考虑过的接口才会用适配器模式,如果一开始就设计为什么不一开始就避免这种情况呢?我认为一开始设计的时候一定要多定义接口,画出类图来,近可能的去覆盖系统的所有功能,细到对每一个对象模型的操作,不用多想尽管去定义,去设计,这样肯定会有很多地方重复,好了,如果感觉定义的差不多了,感觉确实没有什么可以继续定义的了,这时候可以停下来开始下一个阶段了。
现在可以把笔放下,整理一下每一个接口,找其功能相同或者可以合并的方法,去抽象出一个父接口,把能够公用的方法提出来。这样一次一次不断的迭代,最终你会发现越看越顺眼,当然我指的接口不是interface定义的,也可以是一个类或者抽象类,也许有人会提出疑问,那这样定出来的接口系统能够扩展吗?我的回答是在这个领域范围内的一般可以扩展,超过这个领域范围,我还是劝你设计另外一套子系统,谁规定系统扩展一定必须是在代码上扩展。也可是以子系统的方式来扩展,这样某些子系统很多情况下也是可以复用的,举例,Auth,cache,甚至是client与server都可以设计成一个子系统,client与server一定是需要以对象作为载体的吗?xml难道就不行?接口这个东西很有多含义,有些只可意会,无法言传。
以上只是我的一点经验和想法,我很希望各位道友能够给我提出意见,有没有更好的方法,也希望大家能够发表一下自己的方法。
[该贴被zzxsky1986于2010-04-27 22:46修改过]

不错,个人体会是:使用接口将做什么和怎么做分开,怎么做是细节,做什么是目标,就象条条大路通罗马,罗马这个目标要定下来,至于怎么走的细节就不用考虑了。

那么接口中行为方法如何定义呢?个人认为要从职责协作入手,职责协作最后表现为行为方法,但是行为方法的起源。把职责切分到接口中成为其方法。然后实现职责行为之间的交互。用接口实现职责,一个实体实现不同职责的接口。

那么职责如何界定?职责就是对象应该做的事情,比如货物的职责是达到目标地,职责是对象的义务,万事万物生来都有职责,只是你没有发现而已。

对象设计:角色、责任和协作详细谈了职责,可供参考。

SOLID原则DBC也对职责进行了定义,都是我们实现接口的一些原则和模式。

说的很实在。

个人体会是构架、接口、抽象、OO这些东西都会有三个过程。
1.初级阶段:这个阶段,只是听说这些概念,看了下这些东西定义说明。但还不能理解和运用。
2.迷茫阶段:这个阶段是经过一些开发编码阶段后,慢慢的也运用了一些其中的技术和思想,体会到了这些思想的好处,知道要从更高的角度去思考和设计,但是思路拔高后很容易就迷茫了,有点理不清还乱的感觉。鄙人感觉自己现在也处于这个阶段
3.清晰阶段:这个阶段应该是软件大师,banq老师所处的位置。站在真正的高度上面,能很清晰的根据不同的场景,根据相应的原则,提出最好的方案。说出来很朴实,大道至简。而不会像第二阶段说出来感觉很有高度,但很虚,不实在。

回到“接口”,其实就是抽象,通过面向对象来映射最真实的世界。根据面向对象的设计原则,开闭原则,依赖倒转原则,接口隔离原则...,结合设计模式来进行分析。

2010年04月28日 09:33 "banq"的内容
那么接口中行为方法如何定义呢?个人认为要从职责协作入手,职责协作最后表现为行为方法,但是行为方法的起源。把职责切分到接口中成为其方法。然后实现职责行为之间的交互。用接口实现职责,一个实体实现不同职责的接口。

那么职责如何界定?职责就是 ...


"职责协作"的确是一种非常自然的思考方法,避免太飘渺的又难以理解的做法。关于接口,我有个很简单的想法:接口就是需要变化的地方。

接口还是首先要考虑业务过程,一组接口总是要围绕一个核心的业务过程,用于描述一个业务过程所提供的功能。

我的方式是从这个业务过程开始,此时接口的定义往往是可以脱离特定的语言进行描述,此时主要考虑:业务功能、此功能业务过程所需要的数据。

完成了功能的抽象然后再将总结出来的接口应用于实际的语言和调用过程进行检验,这时候可能根据特定的语言附加一些参数,为了调用方便进行一些取舍,等等

个人理解:
interface = inter + face
inter向内负责方法的实现(内建);face对外负责方法的调用(外用)。

interface在此就是给内实现(内建),外调用(外用)之间立一个约定。
这样的好处就是,外用不关心内建,内造不关心外用,彼此相对独立,减少耦合。

这就有点像软件项目中,如果能定下来理想的功能说明书(类比“接口”),那客户与项目人员是非常和谐的。成熟的软件外包行业,想想发包方和接包方,也有助于理解接口。

2010年04月28日 22:28 "youway"的内容
interface在此就是给内实现(内建),外调用(外用)之间立一个约定。 ...

讲得很好,内建应该属于职责责任方面;外用属于协作,协作需要信任度,而提出约定合约则是默认不可信赖的,外用的这个约定也就是Contract,实际就是按照合约设计Design by Contract(简称DBC),这个约定还会分前置条件 后置条件和不变性,前置条件是相对外用而讲,相当于告诉外用,你使用我的前提是什么?使用我后给你什么结果。


凑个热闹...
1.接口适合表示角色,它约定了一个角色应该履行的职责。
2.接口适合做可变性封装,即当你发现某个类有可能有多种实现方式,或者将来可能需要改变实现方式,但于此同时他所扮演的职责(即方法)从名称或参数结构上相对稳定的话,就应该 Extract Inteface 。
3.接口适合作为哪些通过相互协作提供某一系列功能的多个类的入口(Facade)。

2010年04月28日 15:47 "IceQi"的内容
接口还是首先要考虑业务过程,一组接口总是要围绕一个核心的业务过程,用于描述一个业务过程所提供的功能。

我的方式是从这个业务过程开始,此时接口的定义往往是可以脱离特定的语言进行描述,此时主要考虑:业务功能、此功能业务过程所需要的数据。
...


我觉得IceQi讲得很实在,很实用,理论少,方法明确,可操作性很强。
[该贴被atester于2010-04-29 22:49修改过]

一回生二回熟 对业务的理解很重要。

接口是一种定义和规范。就想spring的BeanFactory接口,定义了IOC容器的基本方法,至于具体实现就有具体的实现类去实现好了。
定义好了再去实现他的细节就比较省事了。