简介
面向对象编程(Object-oriented Programming,缩写:OOP)是软件工程中具有对象概念的编程范式(Programming Paradigm),同时也是一种程序开发的抽象方针,与之对应的编程范式还有:函数式编程(Functional Paradigm),过程式编程(Procedural Programming)、响应式编程(Reactive Programming)等。
一切皆为对象
面向对象编程,一切皆为对象,对象是程序额基本单元,对象把程序与数据封装起来提供对外访问的能力,提高软件的重用性,灵活性和扩展性。例如,iOS中的NSObject对象,可以表示iOS中的一切对象。
在面向对象编程中,通常把对象的数据(字段)称为属性,把对象的行为称为方法。
对象与类
在面向对象编程中,最常见的表现就是基于类来表现的,每一个对象实例都有具体的类,即对象的类型(抽象类、基类)。使用类的面向对象编程也称为基于类的编程(Class-based programming),如常见的Java,C++;而与之类似的有基于原类型的编程(Prototype-based Programming),如JavaScript。
- 类:定义对象的数据格式(属性类型)和可用过程(方法),同时也可能包含类成员的数据(如,常量)和过程(如,静态方法),类其实就是对象的类型/原型(prototype)。
- 对象:类的实例,通过类实例化出来的具体实例。
如iOS 中YQViewController *vc = [UIViewController new];
面向对象三大特征
- 封装(Encapsulation)
- 通过对象隐藏程序的具体细节,将数据与操作包装在一起,对象与对象之间通过详细传递机制实现互相通信(方法调用),具体的表现就是通过提供访问接口实现消息的传入传出。
- 封装常常会通过控制访问权限来控制对象的互相权限,常见的访问权限:公有(public),私有(private),保护(protected)。某些语言可能会提供具体的访问控制,如swift中的internal:在本模块中都可以进行访问,默认就是此类型、fileprivate:在当前源文件中可以访问;
- 封装的意义:由于封装隐藏了具体的实现,如果实现的改变或升级对于使用方而言是无感知的,提高程序的可维护性;而且封装鼓励程序把特定数据与数据操作的功能打包在一起,有利于应用程序的去耦。
- 继承(Inheritance)
- 支持类的语言基本都支持继承,继承即类之间可以继承,通过继承得到的类称为子类,被继承的类称为父类,子类相对于父类更加具体化。
- 子类具有自己特有的属性和方法,并且子类使用父类的方法也可以覆盖(重写)父类方法,在某些语言中还支持多继承,但是也带来了覆盖的复杂性。
- 继承的意义:继承是代码复用的基础机制。
- 多态(Polymorphism)
- 多态发生在运行期间,即子类型多态,指的是子类型是一种多态的形式,不同类型的对象实体有统一接口,相同的消息给予不同对象会引发不同的动作。
- 多态的意义:提供编程的灵活性,简化了类层次结构外部的代码,使编程更加注重关注点分离(Separation of concerns,SOC)。
其他特征
- 抽象(Abstraction):能够把复杂问题通过抽象简单化,可以为具体问题找到最恰当的类定义,并且可以在最恰当的继承级别解释问题。
- 组合(Composition):对象可以在实例变量中包含其他对象。
面向对象的基本原则
单一职责原则
一个类或则一个模块应当只有一种职责,其提供的服务应该与其他职责保持一致,如果存在多种责任则应考虑对其拆分。
开闭原则
软件中的对象(类,模块,函数等等)应该对于扩展是开发的,但是对于修改是封闭的
开闭原则主要思想就是对于扩展的包含,对于修改的限制,新增功能的同时避免修改已有的实现,尽量做到对外提供的功能不变。
里氏替换原则
程序中的对象应该是可以在不改变程序正确性的前提下被它的子类所替换的
里氏替换原则认为子类的功能应该可以完全替换父类并且不会影响程序的正确性,简单理解就是子类在继承父类的同时不能改变已有的功能,加上开闭原则子类只能对父类进行扩展而不能对父类的功能进行修改
接口隔离原则
多个特定功能接口要好于一个宽泛用途的接口
接口隔离强调将大而全的接口拆分成小而精的接口,使用方只需关系自己需要的接口,通过接口隔离有利于系统的解耦,增加程序的易用性和拓展性。
依赖反转原则
1.高层次的模块不应该依赖于低层次的模块,两者都应该依赖于抽象接口
2.抽象接口不应该依赖于具体实现。而具体实现则应该依赖于抽象接口
依赖反转原则是指一种特定的解耦(传统的依赖关系创建在高层次上,而具体的策略设置则应用在低层次的模块上)形式,使得高层次的模块不依赖于低层次的模块的实现细节,依赖关系被颠倒(反转),从而使得低层次模块依赖于高层次模块的需求抽象
GRASP面向对象设计
通用职责分配软件模式(General Responsibility Assignment Software Patterns,GRASP),面向对象的设计原则,与SOLID设计原则无关,与GoF设计模式也不太相同,GRASP更像是一个设计思想,是在面向对象设计过程中起指导的作用,是长期面向对象编程过程中经过验证且标准的最佳实践,可以说我们通常所说的设计模式是基于GRASP的。
GRASP告诉我们怎样设计问题空间中的类与分配它们的行为职责,以及明确类之间的相互关系等,下面简单介绍下GRASP的九个原则:
信息专家原则(information expert)
信息专家原则主要用于表明何处委派职责,职责的委派可以是一个方法,字段等。
分配职责的原则
查看给定的职责,确定履行职责所需要的信息,然后确定信息的位置并将其职责分配给它。也就是,将职责分配给拥有履行一个职责所必需所有信息的类。
创造者原则(creator)
创建对象是面向对象系统中最常见的活动之一。创建者原则表明对象的创建应该由哪个类负责创建的原则,如果A和B之间符合下面的规则,则表明A的创建可以分配给B:
实例B包含实例A或者实例B聚合实例A
实例B记录实例A
实例B频繁使用实例A
实例B拥有实例A初始化的全部信息并且在创建的过程中把这些信息传递给A
低耦合原则(low coupling)
耦合是衡量一个元素与其他元素的连接,或依赖其他元素的强弱程度。低耦合是一种评估模式,决定了如何将责任的分配
低耦合设计:
类与类之间的依赖尽可能要降到最小
修改一个类对其他类的影响应该是无影响或者要把影响降到最小
提高系统的复用性
高内聚原则(high cohesion)
高内聚是衡量对象保持适当的集中,可管理和可理解的程度,低耦合通常需要高内聚的支持。
高内聚意味着特定元素的职责是强相关且高度集中的,为了实现高内聚通常做法就是类的划分和子系统的划分,若是划分的元素低内聚也就是职责不明确,那么使用者将会难以理解,程序也难以复用,难以维护。
控制器原则(controller)
控制器模式是通过控制器(Controller)将系统事件或者一类用例分配给对应职责的对象,这个对象可以是类或模块或子系统,控制器不与UI进行交互,它只负责系统事件的调配。
基于用例的控制器应该负责处理该类别的所有用例,并且是支持多用例的(如,用户相关的用例,新增用户和修改用户等应该统一交给用户控制器处理)
虽然控制器不与UI交互,但控制器通常用于UI层之外的第一层,也就是我们经常使用的MVC软件架构种的C层(即控制器层),控制器层起组织协调的作用,负责事件的分发委派并返回处理结果。
多态性原则(polymorphism)
多态性原则即面向对象的三大特征之一,指的是不同的类型实现统一的接口,使在系统运行期间相同消息发送给不同类型的实例而会有不同行为。
在具有多态性的场景下应该使用多态性操作,而不应该使用具体某个类型(如表现在Java中就是使用接口编程,即IOP)
纯虚构(pure Fabrication)
纯虚构是指一个不代表处理某个问题领域的类,专门用于实现高内聚低耦合,提高复用性,这总类在领域驱动设计中被称为服务(Service)。
为了实现高内聚类通常根据功能被划分称为功能集中的类,而这种划分导致使用方需要更多的类从而提高了耦合度,这与低耦合相矛盾,而通过纯虚构可以构造出"虚构类",这种类不是针对某个问题,而是某些能力/功能的抽象划分。(实际使用中例如我们通常使用的分层系统,数据库访问层就属于纯虚构的一种实现)
中介原则(Indirection)
中介模式是指通过一个中介来实现两个对象之间的交互实现低耦合。其目的是为了避免两个对象之间产生直接耦合,降低对象之间的耦合度。
同样的,在MVC设计模式中,控制器(Controller)起到的作用就是作为中介连接其数据模型(Model)与视图(View)
受保护变量原则(protected Variations)
与开闭原则类似,通过使用接口封装系统中存在的不稳定点,并且使用多态操作来使用此接口,从而避免不稳定点影响其他对象(类,模块,子系统等)
总结
面向对象编程其实是一个非常系统非常抽象的话题,这里只对主要概念的介绍以及一些个人的看法。要理解并使用面向对象编程需要通过不断的实践和理解,并且需要一定的抽象能力,通过阅读以后的优秀源码也可以增强自己的面向对象编程意识。如果在面向对象抽象过程中一团雾水的话可以通过画图来整理思路,通过面向对象的设计原则来检查自己的设计与实现,循序渐进不断迭代来提高自己的面向对象编程能力和思维方式。
引用转载链接:https://www.jianshu.com/p/3a81c69134c2
引用转载感想
- 功利的心态始终存在,平时学习的时候没有认真总结
- 对于底层思想没有深刻的理解,挤不出墨水(原文写的很好)
- 感谢原文作者的详细的阐述了面向对象的思想