时间飞逝,一眨眼已经工作7年。趁着最近赋闲在家,对职业生涯做个回顾和总结,避免浮躁和焦虑。

将代码写好是一件难事,我见过刚入行就能把代码写成诗的,也见过工作十年还把代码写成屎的,无论是刚入行的小白,还是工作多年的大佬,都要对面向对象有一个清晰的认知。因为到后边你会发现,我们常说的高内聚、低耦合,三大特性五大原则,甚至是设计模式,都是对面向对象编程思想的补充和扩展,这玩意儿将贯穿我们整个职业生涯,是我们写好代码的关键。

上古时代,很多人对于好代码的评判标准往往是能运行、不出错。但是随着技术的日益更替,优雅,才是我们如今更高的追求。

面向对象

一千个人中有一千个哈姆雷特,每个人对面向对象的看法都不完全相同,我自己每隔一段时间进行回顾,也都会有一些不一样的收获。

首先面向对象是一种软件开发方式,核心思想是将具体事物看作是一个对象,然后对其行为和属性进行封装。

例如:我有一只小狗,将小狗看作是一个对象,那么它的年龄、性别、名字都是它的属性,狗会跑、会叫、会吃东西,都是其行为。

我有一只小狗,你也有一只小狗,当我们对大家的小狗进行共性抽取,也就形成了类:狗。

狗的年龄、性别这些属性,就是类中的数据,跑、叫、吃东西这些行为,也就是类中的方法。

看到这里你可能会说,你没有一只小狗,你有一只小猫,那么对猫和狗进行共性提取,也就收获了类:动物。

对对象共性的抽取,也就是俗称的抽象。

类是创建一个或多个对象的模板,也就是对象的抽象,对象是类的具体实例,通过同一个类创建的多个对象有相同的属性和行为,但每个对象都是独立的,单独操作和修改某个对象的属性,并不会影响其他对象。

面向对象的三大特征

面向对象的三大特征是封装、继承、多态,它们是实现面向对象编程的重要概念和工具。这些特征之间存在紧密关系,彼此相互依赖。

封装

封装是指将数据和对数据的操作封装在一起,形成一个独立的对象。对象通过暴露有限的方法与外部进行交互,对外隐藏内部的具体实现。

简单来说,封装就是套壳,隐藏内部细节。例如你买了一台电脑,你只需要按下开机键,然后就能通过键盘来办公或者玩游戏,完全不需要关心电脑内部是怎样工作的。

封装提供了数据的访问控制,对外隐藏了内部的实现细节,可以保护数据的完整性和安全性,同时,也提高了使用者的便捷性。

是实现继承和多态的基础。

继承

继承是指一个类可以继承另一个的数据和方法,子类可以复用父类的代码,也可以在此基础上添加、修改甚至是覆盖相应的方法。

也可以理解为就是共性抽取,达成复用。例如你买了一辆红色法拉利,你同学买了一辆蓝色保时捷,它们都是车,都有颜色,都能跑,共性抽取后就的得了父类车,保时捷和法拉利都从父类继承行为和属性,到都保持自己的属性值。

继承是为了减少重复代码,降低重复开发的工作量。

是实现多态的基础。

多态

多态是指不同对象的同一个行为将产生不同的状态。

还以上述的车为例,法拉利和保时捷同时在路上跑,但是发动机性能不同,跑的速度不一样,就是多态。

多态是继承的延伸,是为了提高代码的灵活性。

面向对象的五大原则

面向对象开发的基本原则也成为SOLID原则,可以帮助我们设计和实现灵活、可维护和可扩展的软件系统。

单一职责SRP

也就是一个类或模块应该只有一个明确的职责。

不要为一个类安排太多的功能点,类的职责越多,引起它变化的原因也就越多,代码更加耦合,难以维护。

有助于提高代码的可读性和可维护性。

设计模式中的工厂模式,就是一个完美符合单一职责的例子,只有一个职责:生产对象。

接口隔离ISP

单一职责是对类的要求,接口隔离则是对接口的规范,要求我们用多个小而专门的接口,而不是一个大的总接口。

也就是要避免俗称的“胖接口”,类不应该实现它不需要的接口。

适配器模式,外观模式等都是对接口隔离原则的运用。

开闭原则OCP

对扩展开放,对修改关闭,是对继承和多态的引申。

对扩展开放,意味着有新需求或者需求变更时,应对现有代码进行扩展,以适应新的情况。

对修改关闭是指在对现有代码扩展时,不应该影响已有的程序模块。

对应的有装饰器模式,可以动态添加修改类的功能。

里氏替换LSP

里氏替换的核心思想是子类可以替换父类。

核心思想是对继承的约束和规范,避免滥用继承。

比如你定义一个鸟类,其中的一个方法是飞,当鸵鸟继承该类以后,就会发现自己并不会飞,这显然违背了里氏替换。也就是说继承类时要谨慎,不合适的不能随便继承。

里氏替换有以下几个要求:

  1. 子类应该实现父类所有的公共方法,并且输入输出和异常处理等行为要和父类保持一致;
  2. 子类可以添加自己的行为和属性;
  3. 重载父类方法时,方法的前置条件(输入)要比父类宽松,后置条件(输出)要比父类严格;

依赖倒置DIP

依赖倒置原则的核心思想是降低耦合度,主要包括两个方面:

  1. 高层模块不应该依赖低层模块,两者都应该依赖于抽象接口
  2. 抽象接口不应该依赖于具体实现,具体实现应该依赖于接口。

简单来说,就是依赖倒置要求我们面向接口编程,而不是面向具体实现编程。

依赖倒置常与依赖注入结合使用,依赖注入是指通过构造函数或者参数等方法将依赖对象传递给需要使用它们的对象,而不是在使用它们的对象内部创建和管理。

高内聚低耦合

高内聚低耦合是判断软件设计好坏的标准,依照高内聚低耦合的标准来进行代码设计,是为了提高代码的复用性和可移植性。

高内聚

高内聚,顾名思义,也就是高度的内部聚集,是指一个类或模块内部各个元素彼此紧密相关,具有相似的目标和职责。

通俗来讲,也就是自己的事情自己做,自己的东西自己保管。

高内聚的模块都具有明确的职责和功能,使得代码逻辑清晰,易于理解和修改,通常也可以作为独立的功能模块重复使用。

提高内聚,可以同过以下方法:

  1. 确保每个类或模块只负责一个明确的职责,也就是遵循单一职责原则;
  2. 使用继承和多态,将共享的属性和行为提取到父类,然后让子类实现特定的功能,也就是面向接口编程,遵循依赖倒置原则;

低耦合

低耦合是指模块之间的依赖关系要弱,彼此相对独立,一个模块的修改不会对其他模块产生太大的影响。

通俗来讲,就是减少对别人的依赖,也降低别人对自己的依赖,保持自我和独立。

低耦合的设计减少了模块之间的依赖关系,使模块的独立性增强,修改模块时不会牵一发而动全身,简化了维护工作,也更容易组合成不同的系统或应用。

降低耦合,可以通过以下方法:

  1. 使用接口或抽象类来定义模块间的通信协议,也就是遵循依赖倒置原则;
  2. 将每个类或模块的职责限制在一个明确的范围内,避免一个类或模块负责太多的功能,也就是遵循单一职责原则;