享受代码,享受人生

SOA is an integration solution. SOA is message oriented first.
The Key character of SOA is loosely coupled. SOA is enriched
by creating composite apps.
posts - 207, comments - 2305, trackbacks - 147, articles - 44
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

自从有了软件开发以来,消除重复,提高软件的重用性就一直是我们所追求的一个重要目标,本文将围绕着这一主题,带大家重走一遍结构化(SA)、面向对象(OO)与设计模式(Design Pattern)、组建化(Component)、面向方面(AOP)直至面向服务(SOA)这条软件开发技术的发展之路。让我从“重用”这么一个简单甚至是片面的的角度让大家对这些出现在众多文章中的名词有一个比较清晰的认识。虽然结构化,面向对象甚至设计模式已经被大家所熟知,不过"组建化"、"AOP"、"SOA"这些名词的意义可能很多人还尚未了解,而对它们的产生背景就更加陌生了。为什么需要某项新技术,这恰恰是我在深入学习它之前最关心的问题。

结构化编程,恐怕园子里几乎没多少人曾经用过它来开发一个超过1000行代码的程序,我“有幸”在大一暑假(确切地说是大二短学期)完成一个作业的时候经历了一把。在结构化的世界中经常会出现这样或那样的重复,相似的代码随处可见。虽然那时还很菜,不过很自然的,你会把一些常用的函数按功能归纳到各个模块中,在以后的项目中不断地重用它。很明显,此时你会尽量减少使用全局变量,因为在这种时候我们最怕的就是一种被称为“side effect”的问题,也就是你在A处修改了某个变量的值,却无意中影响了B处的结果。这样我们就会尽量把代码模块化,让一个模块中的变量不会被另一个模块使用。Hmmm...难道你没有从中看出封装的影子吗?将变量封装到对象内部,防止外界的修改这不正是面向对象的特性之一吗?那么,原来在结构化中的一个个功能模块此时就变成了面向对象中的一个个类了,对象由此而来。我们知道面向对象有三个重要特性——封装,继承,多态。那么继承和多态又是如何为减少重复代码做贡献的呢?继承相当容易理解,子类继承父类,自然的获得了父类的功能,父类实现功能的代码不用在子类中重复一遍,自然减少了重复。多态就没继承那么直接了。其实多态也正是在初学面向对象编程时,很多人都不理解甚至不知道它有什么用的一个概念。虽然本文的主要目的不是介绍多态,不过我很想就“消除重复”这个话题,谈谈我对多态的理解。

仍旧以计算工资这个老例子为例,有两种类型的员工:正式工、小时工,它们的工资计算方法各不相同。先看一下在结构化中的实现:

int GetSalary(string employeeName)
{
	int baseSalary,bonus;
	if (isOfficalEmploree(employeeName))
        {
         	baseSalary=1000;
                bonus=500*GetRate(employeeName);
         }
	else
        {
                baseSalary=50*GetHours(employeeName);
                bonus=0;
         }
	return baseSalary+bonus;
}
 

现在只有两个类型的员工,计算工资的方法也不复杂,你已经可以从中看到“重复”的影子。我们可以将这种类型的问题归结如下:

if (... )
{
     A();
     B();
     C();
}
if (... )
{
     A();
     B();
     C();
}
//...

函数的处理步骤基本相同,只不过A,B,C在不同情况下(也就是面向对象中的不同类型)有不同的处理逻辑。我们再用面向对象的方法改写上面的例子:

int  GetSalary(Employee employee)
{
	int baseSalary=employee.GetBaseSalary();
	int bonus=employee.GetBonus();
	return baseSalary+bonus;
}
 

重复出现的A,B,C不见了,这不正是减少了重复代码吗?无论什么样的员工,GetSalary方法都可以得到重用。(上面这个例子仅用于说明消除重复这个问题,请不要细究它的设计是否合适)

正是因为这个原因,接口才在面向对象语言中大行其道。

public void UseQueue(IMessageQueue q)
{
	//...
        q.Send("Hello Reusable Method!");
	//...
}
 

上面这段代码意味着什么?使用了IMessageQueue使该方法获得了最大程度的重用性,不论具体的MessageQueue怎么变,该方法总是可以重用的。 (具体例子参见Separate Contract from Implementation一文)

结构化语言在通过模块化,函数指针等等技术的帮助下虽然能部分解决重用问题,但是它已经显得捉襟见肘,此时出现了面向对象语言,在灵活运用封装,继承,多态的基础上,我们最大限度地解决了源代码级的重用问题。注意,此时出现了一个新名词——源代码级的重用。既然有源代码级的重用,那么自然也就有其他级别的重用,显然我们此时已经不满足于在代码层次上的重用。我们希望实现更高级别的重用。其实在面向对象刚出来那会,也并没有多少人能够真正理解该技术并灵活运用其特性提高代码的复用性。没多久,被称为GOF的四个人出了一本书——《Design Patterns》。在这本书中,非常深刻地阐述了应该如何运用面向对象技术以及我们能从中获得的好处,它告诉了我们如何编写可复用的代码,并把软件复用技术提升到了另一个高度——思想的复用。在设计软件的时候,我们可以站在比代码更高的层面来看待如何复用软件设计中的这些模式。现在几乎人人皆知《Design Patterns》这本圣经,可有多少人注意过这本书的子标题呢?——《Elements of Reusable Object-Oriented Software》。

从代码到思想,设计模式完成了一次复用的飞跃。那么还有其他形式的复用吗?随着软件开发技术的发展,更高的复用需求随之而来。

试想一下,如果你在一个项目中需要用到一个以前写过的功能,那么你需要做什么呢?你不得不把以前的代码全部拷贝到新的项目中。过了一段时间,你突然发现这段经常被别的项目重用的代码存在一个bug,需要做一些小的修改,那么你能想象你需要为此付出的代价吗?源代码级别的重用在一个单一的项目中不存在太大的问题,但是面对更高级别的重用——跨项目的重用,就暴露出了它所存在的问题。如何解决?对.NET技术非常熟悉的读者肯定想到了引用了dll组件。将需要被重用的代码放入一个单独的dll组件中,需要使用该功能的项目只要添加这个dll的引用即可。将来被重用的代码发生变化时,只需将这个dll组件更换成新版本即可。此时,你已经在不经意用到了构建化技术(构建,组件均代表了Component这个词)。构建化技术使我们获得了二进制级别的重用,它在一定程度上解决了项目间的复用问题。不仅如此,在某些组件技术中,还实现了跨语言的重用。如在COM以及.NET技术的支持下,我们可以使用VB调用由C++或其他语言编写的组件。而之所以能实现这一点,全依赖于组件的自描述功能,也就是说组件中不仅仅包含一个个类,还额外包含了描述这些类、方法、参数等等的类型信息。也正是由于这些信息的存在,才造就了一个新的编程利器——“反射(Reflection)”。

在OO以及Component技术的帮助下,我们已经能够非常方便地实现一些软件功能的复用。不过这些复用通常是针对那些在一个或多个项目中经常用到的小功能。随着软件技术的发展,软件的规模越来越大,越来越复杂,此时对复用技术又提出了更高的要求。我们希望在两个独立的应用系统之间也能实现复用。即系统A需要某些功能,而恰恰之前的系统B具有这些功能,我们在开发系统A的时候,一种方法就是所有的功能都由自己开发,这样系统的实现形式非常统一,功能交互的方法,参数等等也可以完全由自己控制。但是这样做显然是一种资源的浪费,如果系统B的不是很复杂还可以考虑采用这种方法,但是在大多数情况下,重写系统B的代价是不可接受的。另一个方法就是由系统B暴露出核心功能的接口,之后系统A利用这些接口与系统B产生信息交互,这样实现了系统B在另一个系统中的重用。这种应用系统间的重用在一个企业内部,以及企业与企业之间广泛存在。典型的例子就是对遗留系统的重用以及对外部系统的重用。在这种情况下,系统A与系统B分别运行在两个独立的进程中,他们可能在同一台机器中,也可能在两台不同的机器上。为了实现功能的交互,我们不可避免的要用到分布式对象技术。通过组件中的类型元数据,我们可以轻易地在客户端生成远程对象的接口,并进一步创建出代理对象实现客户端对远程对象的访问。Remoting中的Soapsuds.exe就是在.NET的分布式系统中实现此类功能的一个工具。所以说组件技术在实现应用系统间复用的时候也起了相当重要的作用。

现在让我们再回过头来看看面对对象技术的应用在这种分布式环境下又发生了怎样的变化。首先需要注意的是系统B并不需要将它所有的业务对象暴露出来供系统A使用,我们需要重用的是系统B的功能,此时我们通常会利用Facade模式将系统B的核心功能集中到一个Facade对象中,所以继承、多态这些面向对象特性在分布式对象中基本上是用不到的。其次,Facade对象中的方法都是粗粒度的,也就是说其中的一个方法通常是完成一次性完成一个复杂的功能。比如,你不可能像下面这样使用一个远程对象:

Person p=RemoteGatway.GetPerson("idior");
p.Age=24;
p.Sex=Sex.Male;
//...

而应该采取类似下面的方法:

Person p=RemoteGatway.GetPerson("idior");
p=p.SetBaseInfo(new PersonInfo(24,Sex.Male,...));
 

这样做的原因是避免产生过多的网络调用,而在这一点上普通对象恰恰与此相反。另外为了实现性能上的scalability(伸缩性),Facade对象通常是无状态的(具体内容参考Distributed Application --- Applying Remoting & Enterprise Service)。由此看来,为了实现系统间的交互,Facade对象基本上完全丧失了面向对象中一个对象应该具有的特性,我把这种对象称之为服务对象。面对服务的概念呼之欲出。不过这些分布式对象往往局限于某个特殊的分布式技术,比如.NET的Remoting、Cobra或者是EJB,如果系统A与系统B都是采用的同一种技术,那么就不存在太大的问题。不过在实际的应用中,又哪来那么多巧合呢。如果一个.NET的应用想与一个Java应用交互,可想而知这是一件多么困难的事情。并且在企业的应用中我们不可能不考虑整个系统的安全性以及事务性,让两个不同的分布式系统配合起来工作并保证安全与事务几乎是件不可能完成的任务。然而这种性质的重用需求又是如此的广泛,终于,为了解决此问题,我们迎来了SOA。

SOA最关键的一个特性就是loosely coupled(松耦合)。现在你应该能够明白为什么这点最为重要了,为了实现异构系统间的集成,服务只有具备了松耦合的特性才能彼此交互。SOA中的服务就是之前提到的Facade对象的升级版,只不过用于描述服务的元数据以及用于调用服务的方式都必须具有松耦合的特性,即不依赖于特定的平台。对比我们之前提到的组件技术,它也提供了服务对象的元数据,但是这些元数据的描述是与具体的组件技术相关的,而调用组件中对象的技术也是依赖于某一特定平台的。为了获得松耦合的特性,我们采用了Web Services技术作为SOA的具体实现。其中WSDL用于描述服务的元数据,而SOAP则规定了如何调用服务并返回结果。这些规范都是符合特定标准的,而各个厂家也都将遵循这些标准。事实上之前提到的Facade对象,在Java下往往会由EJB中的Session Bean实现,在.NET下可以用企业服务中的ServicedComponent实现,而在各自的环境下都可以方便地将该对象升级为Web服务。如在JBuilder中可以使用某些菜单项方便地将一个Session Bean发布成一个Web Service,而COM+1.5也提供了SOAP Services的功能,利用它可以非常简单地将一个ServicedComponent以Web Service的形式发布。

由此,我们可以看出SOA较好地解决了应用系统间的重用问题。SOA是一套系统集成的解决方案,它与传统的分布式对象技术的主要区别在于它的松耦合性。

最后提一下AOP,之前我们谈到的重用都是针对一个功能的实现,你可曾想过调用功能的重用问题。任何一个功能为了使用它,你必须调用相应的对象中的某些方法。而这段调用代码如果不断地出现在你的代码中,你难道不觉得它是一种重复吗?举个简单的例子,为了记录系统的行为,我们经常需要一个日志,而记录日志的方法调用几乎散布在系统的每个角落。我们多么希望能够只在一个地方定义一次调用代码,就能够记录下所有的日志。AOP或许能够帮你解决此类问题,具体内容可以参考我之前写的一篇文章No Buzzword AOP

综上所述,我们可以发现,软件的重用问题一直贯穿了软件开发技术的发展。本文也正是从该角度对目前繁杂的开发技术做了一个大概的介绍,希望对大家理解这些概念有所帮助。

推荐文章:

WS-Coordination简介

WS-Addressing 从理论到实践 --- SOA基础规范介绍

Web Services Security系列文章

Distributed Application in .Net

后记:

写这篇文章的时候发现自己底子实在太薄,中途都想放弃,结结巴巴总算是完成了。现在觉得文章越来越难写,希望自己能坚持下去。还有一点我发现我文章的读者潜水的居多啊,基本在评论中没啥交互。

Feedback

#1楼    回复  引用  查看    

2006-12-29 14:04 by 浪子      
"还有一点我发现我文章的读者潜水的居多啊,基本在评论中没啥交互。;)"

呵呵,曲高则合寡......

高处不胜寒哦~~~~

#2楼    回复  引用    

2006-12-29 15:02 by ocean2000[匿名] [未注册用户]
一路读下了,对于这么多技术的目的:减少重复劳动,有了深刻的认识。

#3楼    回复  引用  查看    

2006-12-29 16:59 by 谢平      
写得不错,继续努力.文章嘛有晦涩难懂得,一大堆专业术语,一大堆理论论证也不能一直看啊.稍微轻松点得看得还不错
不过我不赞同技术得目的是为了减少劳动.我觉得作为写程序的来讲,技术的目的是容易用来把握大方向,考虑方向的时候而不用考虑细节.

#4楼    回复  引用  查看    

2006-12-29 17:21 by 韦恩卑鄙      
收到不少教育

#5楼    回复  引用  查看    

2006-12-29 17:23 by 非我      
不错,看得出来是很用心的写的,这些概念平时也陆陆续续的接触过,不过这样一气呵成的感受还是第一次,谢谢楼主~

#6楼    回复  引用  查看    

2006-12-29 20:43 by microshot      
看ing,3x

#7楼    回复  引用    

2006-12-29 22:16 by 5586002 [未注册用户]
写得不错,其实软件开发技术的发展由于业务应用的发展而发展的!

#8楼    回复  引用  查看    

2006-12-29 22:56 by 随心所欲      
都是懒人,想找更快的方法而已。

#9楼    回复  引用  查看    

2006-12-30 09:26 by 快乐尘埃      
写的不错,后面的写的再详细点就好了。

#10楼    回复  引用  查看    

2006-12-30 13:41 by 辉郎      
我想搂主如果将这篇文章分成几个文章来写会更好。因为这样大范围的论题一口气不论是写来还是读来都总会让人感觉喘不过气来。我们可以分解成多个论题来讨论,这样我们才可能找到一些比较适合讨论的细处拿出来品一品,您嗦4不4?

#11楼 [楼主]   回复  引用  查看    

2006-12-30 14:37 by idior      
@辉郎
原先我也是准备将文章分为两部分,不过考虑文章的完整性,我还是合在一起发布了。在本文中涉及的知识点确实很多,会让人有喘不过气的感觉,不过我之所以写这篇文章就是试图以一个主线将这些技术串联起来。总之,分与不分各有利弊吧。不过还是希望听到更多的意见。

@快乐尘埃
后面的内容确实说的不够详细,不过实在很难在一篇文章中将这么多技术说清楚。本文的目的主要在概述吧。以后有机会再详细介绍其中一些话题。

@All
谢谢大家的支持。

#12楼    回复  引用    

2007-01-04 21:17 by NaNa[匿名] [未注册用户]
是我同事推荐我来看的,果然不虚此行,能够把这五个阶段描述地如此连贯和形象不简单呀,尤其是关于SOA和AOP的解释比较容易理解。关于反射和AOP的应用,我觉得可以从DNN里学到很多好的开发例子

#13楼 [楼主]   回复  引用  查看    

2007-01-04 21:32 by idior      
@NaNa[匿名]
谢谢支持,写这种类型的文章往往读者不太多,因为大家往往更注重实际应用,能得到你们的支持非常高兴。

#14楼    回复  引用  查看    

2007-01-05 16:45 by 燎原星火      
写的满好的,也说明世上无新事, 不错!

#15楼    回复  引用  查看    

2007-01-11 09:25 by JoeHuang      
辛苦了!

#16楼 [楼主]   回复  引用  查看    

2007-01-11 21:32 by idior      
谢谢上面两位! :)

#17楼    回复  引用    

2007-01-12 19:07 by 无力作答 [未注册用户]
看了你的文章后对SOA,AOP等有了进一步的了解~~学习一门技术,首先得知道这技术能解决我们项目中的什么问题,这个思考的过程很重要。谢谢楼主

#18楼    回复  引用  查看    

2007-01-12 19:18 by yinh      
不错,其实我以前也一直在想写一篇类似的文章,或者做一个类似的讲座,把这些技术整个走一遍,让team的人明白技术为什么要这样发展,还有就是让人明白,这些看着很牛比的名词后面包含的仆实的意义是什么。

因为有很多人是半路起家的,如果没有对以前知识的很好理解,我想他是不能较好的掌握现有知识的。

唯一觉得不够过瘾的就是我觉得可以再细一下,在技术方面可以再讲细一些。一些具体的实现也可以稍带着讲一下就完美了。

说实话,看过那么多SOA的描述,除了本文,其它的都只会让初学者越来越不知道SOA。。。。

#19楼 [楼主]   回复  引用  查看    

2007-01-12 20:40 by idior      
@yinh
没错,我也觉得不过瘾呢。有些地方没说细,不是不想而是怕写乱了,其实这种东西讲给有感觉的人听,会比较过瘾。

虽然文章很难写,不过这么一路写下来,还是蛮过瘾的,有机会交流一二。:)

#20楼    回复  引用    

2007-01-17 09:19 by JustRun1983 [未注册用户]
对AOP,SOA有了认识,谢谢

#21楼    回复  引用    

2007-01-17 09:23 by JustRun1983 [未注册用户]
我觉得技术的入手应该是从技术产生的背景和原因讲起,从它的婴儿阶段开始。
现在的技术文章,只是介绍应用,从技术的成人阶段开始,让人摸不到头脑。

#22楼    回复  引用    

2007-01-17 10:31 by happy2006 [未注册用户]
非常好的文章!工作多年,匆匆忙忙,很少将软件发展这条线理得特别清楚,今天获益良多,谢谢!

#23楼    回复  引用    

2007-01-17 16:19 by Jeansliang [未注册用户]
真是不错的美文啊,作者功底深厚。

#24楼    回复  引用    

2007-01-19 10:02 by kevin [未注册用户]
楼主留下mail啊,呵呵,以后交流啊,基实我做程序员有一段时间,范的错误都很经典,我想这样不一定不好,知冷知热嘛,oo,ooa,ood,我想程序员做东西还是多想,
多看看,谢谢楼主,文章写的很精彩.

#25楼    回复  引用    

2007-01-19 11:36 by G.A. [未注册用户]
受益匪浅,我在CSDN潜水很久了,这个文章一定要回

#26楼    回复  引用    

2007-01-20 21:10 by refractedlight [未注册用户]
LZ从代码重用这个角度分析了技术的发展路线,不错.从我们这些几乎没写过c语言的这代人.大致了解了它的成长路线.
内容很多,概念很多.还得细细品味品味.

#27楼    回复  引用    

2007-01-21 23:35 by tlb [未注册用户]
内容不错!
不过俺觉得SA,OO,COMPONENT,SOA应该是软件领域的重用思想的演化,每个阶段都对应一个重用体(函数,类,组件,服务-进程)。

相比之下,AOP更多地是编程技术上的一种进步,它也具有新的思想,但是这个思想性仅仅算作是COMPONENT级别上的一种技术。

#28楼    回复  引用    

2007-01-22 11:14 by sse [未注册用户]
我是一个才毕业2年的新人,但也感受到这篇文章的目的,启发不少。
我很同意其中一个楼上的话,也是最大的感受“学习一门技术,首先得知道这技术能解决我们项目中的什么问题,这个思考的过程很重要。”,这是一个很不错的学习方法。但我知道,要达到作者的高度还有慢长的路啊。大家互勉。

#29楼    回复  引用  查看    

2007-02-14 14:09 by 一辉      
写的不错!将众多的技术利用一条线索串联起来,期待后续沿着这一思路将一些问题更详尽的展开。

#30楼    回复  引用    

2007-02-27 14:48 by clamphammer [未注册用户]
源代码的重用->二进制组件的重用->以业务为单元的业务组件重用(soa)
基本是从软件领域逐渐过渡,越来越接近到业务领域,这个与软件的价值链是一致的,最终体现是为客户提供的价值.
软件领域重用的东西很多,包括文档,开发过程,最佳实践等.

#31楼    回复  引用  查看    

2007-03-02 16:56 by 棠棠dotNet      
难得的文章!感谢楼主!从中明白了些以前理解不到的东西!

#32楼    回复  引用  查看    

2007-03-28 15:20 by 生米煮成稀饭      
支持作者!

#33楼    回复  引用    

2007-04-06 11:03 by flyfoxs [未注册用户]
是太长了,一口气看不下来,我在几天前定了你的RSS

#34楼    回复  引用  查看    

2007-05-29 09:59 by Anders06      
很有份量的文章

#35楼    回复  引用    

2007-06-03 15:57 by netfetch [未注册用户]
SOA考虑更多的一方面是重用性,构件化
http://www.netfetch.cn/netfetch/article.asp?id=942
不过我认为安全性更不可小视

#36楼    回复  引用  查看    

2007-06-04 21:30 by xc#      
学习 留名

#37楼    回复  引用  查看    

2007-06-07 16:50 by DavidFa      
确实感觉很不错,从历史讲过来,让我们在接受新技术的同时知道了为什么。好文章!
潜水的多~~
可能都象我一样吧,我在CNBLOGS潜水半年多了,主要是感觉自己还比较嫩,先多学,多看,看的多了也就有的交流了。

#38楼    回复  引用    

2007-08-31 10:18 by zhoucloud [未注册用户]
一直以来对SOA和AOP的概念都比较模糊,看了LZ的文章清楚了很多,谢谢你的经验分享

#39楼    回复  引用    

2007-10-05 10:58 by ibloom [未注册用户]
很是受启发,尤其是对SOA的讲解。赞一个!

#40楼    回复  引用    

2008-01-18 11:28 by ly611919 [未注册用户]
说实在的,我觉得您的文章是用心写的,是真正为了让别人理解您意思的。
看过很多类似文章,都在那里用些晦涩高深的语言表述自己,很难让众人理解。您的文章写的很好,让人一口气读下来,只感觉那里曾经被说的那么复杂的东西就是这么简单。
呵呵
写的非常好!
希望能有机会与您多交流,多请教您!

#41楼    回复  引用    

2008-01-21 00:16 by 小白鼠 [未注册用户]
写得真好,呵呵,受用了。

#42楼    回复  引用    

2008-03-11 01:02 by 飞翔在平流层 [未注册用户]
跟着楼主的思路,谢谢让我明白了重用的发展阶段

#43楼    回复  引用    

2008-05-21 15:31 by jim.chb [未注册用户]
写得蛮好的呀,最近面试的时候被问到了对 SOP, OO 的认识。 idior的文章的确不错!

#44楼    回复  引用    

2008-08-08 11:02 by Daniell [未注册用户]
路过路过,这篇文章没啥看头

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2007-01-22 19:51 编辑过


相关链接: