dream00csdn 2012-03-31
今天走在路上,思考有些程序员对面向对象,面向过程的差异。我把自己考虑的内容,记录下来。
面向过程在执行Main函数的时候,是一大段代码。它也想到进行改进。方面进行复用。所以,在面向过程中,产生了模块的概念。
举一个例子。(面向对象的多态性)
如果有5个算法,需要在5个算法之间进行切换。
在面向过程的方面是,建立一个模块,然后将5个算法函数放入到一个算法模块中。其中每个函数的名字必须不一样。
在面向对象中,建立一个接口,实现5个类,类名不一样,但函数名一样。
A、在无在XML配置化或者IOC注入情况下
在main函数中,面向过程是Switch选择不同的函数,面向对象时Switch选择不同的对象,执行的同样方面。在测试的时候,基本查不多,因为都要对Main函数进行重新测试。面向对象的好处在于,函数名一样,类名不一样。这样语义可以表现得更加丰富。但本质上没有什么变化。
B、在有在XML配置化或者IOC注入情况下
面向对象,可以将类名放入到xml中,在main中,进行读入然后进行实例化,然后调用统一的方法。
IOC注入的时候,将父类放入到main中,然后在xml中,写入子类进行注入(需要注意在main中,要有该类的set方法
在面向过程中,因为面向过程的编译器不支持将函数名读入,进行动态编译。
产生的差异是软件工程的可维护性,可扩展性的差异。整体软件稳定性的差异。
因为,如果采用面向对象的设计方式(即编译器是支持面向对象的实例化等特征),那么增加一个算法,只要增加的那个算法进行单元测试,并且xml变化一下。main函数不要进行单元测试。这样比起面向过程的main函数要全部测试一次,代价要小很多,尤其是项目中大量采用类似的方式,回归测试的压力会小很多,并且稳定性会非常好。
面向对象具有继承的特征,这样可以使得代码量减少。但是面向过程不具备这个特征。最主要的原因是面向对象的编译器支持这种特征。但面向过程的编译器不支持该种特征。
面向对象具有封闭性,在面向过程域的时候,模块无法做到哪些方面是Private,哪些方面是Protect。但面向对象可以具有明确的动作封装性,仅仅暴露Public。面向过程要全部暴露。这个特征也是编译器提供支持的。
面向对象具备状态,每个对象具有一定的语义。面向过程仅仅是动作,没有状态的语义。
比如在Jbpm中的task,他既有动作特征,也具备属性特征。这些内容进行封装之后,就会出现人类认识事物的本质是属性与动作的统一。面向过程的设计,是将动作与属性进行隔离,使得人在认识这个事物的时候,要从数据,控制2个层面深入抽象分析。分析的复杂度大大提高,对于大型程序的构建,复杂性就会出现无法把握的状态。
在面向对象中,对象的一些动作时依赖与属性的,必须要在Client端先设置一些属性,或者先调用几个方面,让对象中的属性状态改变之后,才能调用在方法中引用该属性。这个问题的本质是类责任的划分。在内存空间中,有一个专门的对象空间,他的状态的变化,以及哪些方面依赖于状态的变化,能够很容易的看到。对状态及方法的统一,作为该类的责任。所以会产生UML设计方面的状态图,并且在内存中,有调试工具,可以看到对象之间调用以及调用之前的属性设置。
人的思考过程是面向对象,还是面向过程?
在没有面向对象编译器支持之前,人的思考方式是面向过程中。因为有一个逻辑主线,但复杂度大大加深,并且测试困难,可维护性降低,程序升级困难。
有了这些问题之后,产生了新的设计方法学,及多态,继承,封装。首先让编译器支持这样的特征。编译器有了这些特征之后,人思考问题的方面就可以进行如下调整。
1、仍然有一个逻辑主线,类似Spring启动的时候,有一个顺序执行的过程。
2、重要的是,类的职责的划分,将有一些责任,复合人类语义的方面,进行划分。面向对象的本质上是降低人理解计算机行为的难度,让多态,封装,继承这些计算机能做的工作,交给后台计算机去处理。
3、职责划分明确之后,设计一些接口,在主程序进行调用。在不同的类中进行实现。要看Spring,Struts,Jbpm源码等,就要先了解这个框架执行的功能,然后看设计者将类责任的划分。
4、在具体的某一个类实现中,还是按照面向过程去思考,注意2点不同
第一个点是:类的责任要从面向过程中一整块进行划分为不同的类来进行执行,
第二个点是:一旦碰到未来需要扩展点,就需要按照面向对象的方面进行拆分。拆分结束后,按照面向过程中进行实现。实现过程中,如果发现具体的类如果有继续变化的点,那么就继续按照面向对象的方式进行拆分。
所以在面向对象的设计过程中,要考虑面向过程的逻辑主线,更为重要的是要考虑在主线中有哪些变化的,可以通过接口进行隔离的。
如自己设计一个事情机制。
逻辑主线是事件源产生事件,(变化点可能多多个事件源,可能产生多个事件种类),事件的注册,事件的通知,事件的执行。这些逻辑概念完全可以在一个类中按照面向过程的方面写出来。但面向变化不够,程序可扩展性大大降低。
采用哪个面向对象的设计方法
设置几个类名词:客户端、事件源、事件对象,事件注册、事件执行
客户端负责创建事件源,创建事件对象,将事件源与事件对象进行关联(事件源事件对象可采用桥接模式),然后firevent(即调用事件注册者的notify动作),这个类不需要知道如何通知事件的,因为责任不在这个类中。他仅负责顺利的调用这个notify动作就可以了。
事件注册:该类中的notify,通知所有在本类中注册的事件,所以需要具备list集合,add,remove的方法。
事件执行,每个事件执行动作中,要判断事件是否是自己要响应的种类,如是,即执行自己的方法。
从
面向对象中6大设计原则的理解
1、类单一责任原则,在前面全面描述过
2、依赖倒置原则,高,低层全部依赖接口。这样可以实现工厂化并行生产,可规模化提高效率。
3、迪米特法则:朋友越少越好。保证内聚性,便于进行测试。这是类责任划分时候的一个原则,不能划分类责任结束之后,各个类之间都要依赖。这个原则也是判断设计者在类划分原则的时候,是否科学。因为在类划分的时候,每个设计者都会不一样,但那个更好,这个原则就是检验的标准。
4、接口隔离原则,在实现类的时候,如果每个类全部单一责任,类的数量会很多,但可以保证接口单一。这样可以更好的保持封装性。如一个类可能有2个接口,一个是窄接口,一个可能是宽接口。
5、里斯替换原则:所有父类的地方,子类都能进行替换,这个事面向接口编程的一个主要理论依据(面向接口编程,可实现变化点采用注入的方面,保证某个类实现变化后,高层不需要进行任何变化(需要采用XMl的方面,注入)
)
6、开闭原则,面向修改关闭,面向扩展开放。是应用上面5个原则之后,达到的效果。
还有一些设计模式,修改是不变的,开闭原则