浅谈OOP
了解Java或C#等面向对象编程语言的的程序员比较熟悉类和对象以及OOP。
一谈起OOP,就会想起教科书式的OOP概念:封装、继承、多态。粗浅的解释封装就是对数据进行隐藏;继承就是子类继承父类(class)或接口(interface)的方法和属性,并实现代码复用;多态就是重载和重写。这样的解释仍仅仅只是面向对象的基本特征,很浅显,根本无法让人知道如何去思考和设计面向对象编程。
面向对象理解
在做面向对象编程时,我们首先应该理解面向对象。
下面是我个人对面向对象的浅薄理解,由于自己做编程也没多久,对OOP理解有限,对设计模式更是一窍不通。
- 抽象的理解:抽象是从众多物质中抽取共同的、本质的特征,抽象是一种概念(比如public interface或抽象基类),抽象的过程是一个比较的过程,有比较才能抽象出共有特征和本质;抽象的过程也是一个裁剪的过程,剪掉非本质的特征。从不同的角度去对事物进行抽象,能够衍生出不同的接口,这些看待或比较事物的角度也可以称作接口。
- 一切事物都是对象,把事物的外观抽象为对象属性,事物的隐私看作为对象字段,事物的外部行为抽象为对象的公共方法,事物的内部行为看作为对象的私有方法。属性和公共方法称为接口,字段和私有方法称为本源。
- 一切private成员或者接口和基类对象作为方法参数都实现了数据的隐藏,把接口和基类作方法参数同样实现了多态性,private成员是对象的内部行为和形态,private成员是对象的本源,private成员无法被继承。
- 一切public成员都是接口,这里的接口就不仅仅是interface,它是一种标准和规则(比如定义的public属性),是对象表现的外部行为和形态,是对象和对象之间的通信和交互的纽带。
- 类继承的意义不仅仅是代码复用,更大的意义是类扩展,类扩展表现为方法的重载以及子类中有的方法和属性而父类中没有的方法和属性。在一定程度上,类扩展也可以看做是一种多态,这不仅仅表现在子类重写父类的方法,还表现在子类比父类具有更多的特性,子类是父类的变体,表现出和父类相似但比父类更丰富的形态。
- 方法的重载表现在“殊途同归”,对象做同样的事情,事情的结果相同(返回值类型),但是实现的途径不同(参数列表或方法体不同)。方法的重写表现在“青出于蓝而胜于蓝”,子类覆盖父类的方法并进行扩展,如果不是这样,重写就没有太大的意义。
- 面向对象(OO)和面向过程(OP):面向过程是基于流程的设计和分析,一个问题的解决或功能的实现需要按照先后顺序很步骤,每个步骤可以是一个函数;而面向对象是基于抽象的设计和分析,从问题和功能中抽象出类和接口,把方法原子化,类单一化。面向对象语言中一切事物都是对象,在面向过程中,方法称之为函数或过程,面向对象中方法是对象的表现行为,面向对象是对面向过程的封装。
面向对象的原则
头五项原则是关于类设计的,它们是:
- SRP,单一职责原则,一个类应该有且只有一个改变的理由。
- OCP,开放封闭原则,你应该能够不用修改原有类就能扩展一个类的行为。
- LSP,Liskov替换原则,派生类要与其基类自相容。
- DIP,依赖倒置原则,依赖于抽象而不是实现。
- ISP,接口隔离原则,客户只要关注它们所需的接口。
另外的六项是关于包的设计原则。在本文中,包是指一个二进制的可发布文件,比如.jar文件、或dll文件,而不是Java包或是C++的命名空间(译注3)。
头三项包原则是关于包内聚性的,它们会告诉我们该把什么划分到包中:
最后的三项原则是关于包之间的耦合性原则的,并且论述了评价系统中包结构优良与否的评判标准。
虽然一些大师们总结了这些原则,但是原则只是一种标准,我们应该效仿标准,而不是依赖标准,在实际的软件设计中,如何能方便快捷的实现需求和客户目标才是关键,过度遵循原则会使简单的问题复杂化,给自己和团队带来不少麻烦。