Java基础1:面向过程与面向对象、三大基本特征、五大基本原则

一、前言

  本文内容摘自《深入理解Java核心技术:写给Java工程师的干货笔记(基础篇)》一书,2022年出版,作者 张洪亮(@Hollis),阿里巴巴技术专家,著有《Java工程师成神之路》系列文章,《Java工程师成神之路》电子书已开源,可在阿里云开发者社区免费下载。书籍内容比电子书内容要丰富,内容有修改,有需要的读者可以购买正版书籍。
 
  【如何成神:先搬砖,再砌砖,后造砖!】
 
  本文由 @大白有点菜 原创,请勿盗用,转载请说明出处!如果觉得文章还不错,请点点赞,加关注,谢谢!

  《Java工程师成神之路》下载地址为:
  https://developer.aliyun.com/ebook/395?spm=a2c6h.20345107.ebook-index.24.4c927863j10ats

深入理解Java核心技术:写给Java工程师的干货笔记(基础篇)

二、第1章 什么是面向对象

1、面向过程与面向对象

(1)面向过程(Procedure Oriented):是一种以过程为中心的编程思想,是一种自顶而下的编程模式。

  代表:C语言。

  简单说,程序员把问题分解成一个个步骤,每个步骤用函数实现,依次调用。

  典型用法:简单算法,如冒泡排序。

  优点:代码执行效率高。

  缺点:代码重用性低、扩展能力差、后期维护难度大。

(2)面向对象(Object Oriented):是一种对现实世界的理解和抽象的方法。通过对现实世界的理解和抽象,运用封装、继承、多态等方法,通过抽象出对象的方式进行软件开发。

  代表:Java、C#、C++、Python、Ruby、PHP。

  简单说,程序员把问题分解成一个个步骤,对每个步骤进行相应的抽象,形成对象,通过不同对象之间的调用,组合解决问题。例如,要造车,先定义车的各种属性,将各种属性封装在一起,抽象成一个Car类。

  优点:代码扩展性、可维护性高。
 

2、面向对象的三大基本特征

(1)封装(Encapsulation):把客观事务封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的类或者对象隐藏信息。

【举个例子(非书中例子)】
  手机提供了计算器的功能,用户只知道计算器可以用来算数,但不清楚内部的逻辑处理算法,计算器对内部算法私有化了,只对外提供计算功能。

【封装举例(书中例子)】
  定义矩形Rectangle类,通过封装的方式,给“矩形”定义了“长度”和“宽度”,“矩形”也就被抽象了。

/**
 * 矩形
 */
public class Rectangle {
    /**
     * 长度
     */
    private int length;

    /**
     * 宽度
     */
    private int width;

    /**
     * 设置矩形的长度和宽度
     * @param length 长度
     * @param width 宽度
     */
    public Rectangle(int length, int width) {
        this.length = length;
        this.width = width;
    }

    /**
     * 获得矩形面积
     * @return
     */
    public int area() {
        return this.length * this.width;
    }
}
public class EncapsulationApp {
    public static void main(String[] args) {
        Rectangle rectangle = new Rectangle(2, 4);
        System.out.println(rectangle.area());   // 8
    }
}

(2)继承(Inheritance):可以使现有类的所有功能,并在无须重新编写原来的类的情况下对这些功能进行扩展。通过继承创建的类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”、“超类”。

【继承举例(书中例子)】
  定义一个正方形,因为有了矩形,所以直接继承Rectangle类。

/**
 * 正方形,继承自矩形
 */
public class Square extends Rectangle {
    /**
     * 设置正方形边长
     * @param length
     */
    public Square(int length) {
        super(length, length);
    }
}
public class InheritanceApp {
    public static void main(String[] args) {
        Square square = new Square(6);
        System.out.println(square.area());  // 36
    }
}

(3)多态(Polymorphism):一个类实例的相同方法在不同情形下有不同的表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。
 

3、面向对象的五大基本原则

SOLID原则:
  单一职责原则(Single-Responsibility Principle)
  开放封闭原则(Open-Closed principle)
  里氏替换原则(Liskov-Substitution Principle)
  接口隔离原则(Interface-Segregation Principle)
  依赖倒置原则(Dependecy-Inversion Principle)

(1)单一职责原则(Single-Responsibility Principle)核心思想:一个类最好只做一件事,只有一个引起它变化的原因。

  单一职责原则可以看做是高内聚、低耦合在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。

  高内聚、低耦合是软件工程中的概念,是判断软件设计好坏的标准,主要用于程序的面向对象的设计,主要看类的内聚性是否高、耦合度是否低。目的是使程序模块的可重用性、移植性大大增强。
 
  内聚是从功能角度来度量模块内的联系的,一个好的内聚模块应当恰好做一件事,它描述的是模块内的功能联系;耦合是软件结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度。

  职责过多,可能引起它变化的原因就越多,这将导致职责依赖,相互之间就产生影响,从而大大损伤其内聚性和耦合度。

  通常意义下的单一职责,就是指类只有单一功能,不要为类实现过多的功能点,以保证实体只有一个引起职责变化的原因。

  交杂不清的职责会使得代码看起来特别别扭,牵一发而动全身,有失美感,甚至可能导致不可预期的系统错误风险。

(2)开放封闭原则(Open-Closed principle)核心思想:软件实体应该是可扩展的且不可修改的。也就是说,对扩展开放、对修改封闭。

  体现在两个方面:
  1)对扩展开放,意味着当有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
  2)对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对其进行任何尝试的修改。

  实现开放封闭原则的核心思想就是对抽象(如接口、抽象类等)编程,因为抽象相对稳定。让类依赖于固定的抽象,所以修改就是封闭的;而通过面向对象的继承和多态机制,又可实现对抽象类的继承,通过覆写其方法来改变固有行为,实现新的拓展方法,所以就是开放的。

(3)里氏替换原则(Liskov-Substitution Principle)核心思想:子类必须能够替换其基类。这一思想体现为对继承机制的约束规范,只有当子类能够替换基类时,才能保证系统在运行期内识别子类,这是保证继承复用的基础。

  在父类和子类的具体行为中,必须严格把握继承层次中的关系和特征,将基类替换为子类,程序的行为不会发生任何变化。同时,这一约束反过来则是不成立的,子类可以替换基类,但是基类不一定能替换子类。

  里氏替换原则主要着眼于对抽象和多态建立在继承的基础上,因此只有遵循里氏替换原则,才能保证继承复用是可靠的。

  里氏替换原则是关于继承机制的设计原则,若违反了里氏替换原则,则必然导致违反开放封闭原则。

  里氏替换原则能够保证系统具有良好的拓展性,同时实现基于多态的抽象机制,能够减少代码冗余,避免运行期的类型判别。

(4)接口隔离原则(Interface-Segregation Principle)核心思想:使用多个小的专门的接口,而不要使用一个大的总接口。

  在父类和子类的具体行为中,必须严格把握继承层次中的关系和特征,将基类替换为子类,程序的行为不会发生任何变化。同时,这一约束反过来则是不成立的,子类可以替换基类,但是基类不一定能替换子类。

  具体而言,接口隔离原则体现在:接口应该是内聚的,应该避免“胖”接口。一个类对另外一个类的依赖应该建立在最小的接口上,不要强迫依赖不用的方法,这是一种接口污染。

  接口有效地将细节和抽象隔离,体现了对抽象编程的一切好处,接口隔离强调接口的单一性。而“胖”接口存在明显的弊端,会导致实现的类型必须完全实现接口的所有方法、属性等;而在某些时候,实现类型并非需要所有的接口定义,在设计上这是一种“浪费”,而且在实施上这会带来潜在的问题,对“胖”接口的修改将导致需要修改一连串的客户端程序,有时这是一种灾难。在这种情况下,将“胖”接口分解为多个具体的定制化方法,使得客户端仅仅依赖它们的实际调用的方法,从而避免客户端要依赖于它们根本用不到的方法。

  分离接口的手段主要有以下两种:
  1)委托分离,通过增加一个新的类型来委托客户的请求,隔离客户和接口的直接依赖,但是会增加系统的开销。
  2)多重继承分离,通过接口多继承来实现客户的需求,这种是较好的方式。

(5)依赖倒置原则(Dependecy-Inversion Principle)核心思想:程序依赖于抽象接口,而不是具体的实现。简单地说,就是要对抽象进行编程,不要对实现进行编程。

  在面向过程的开发中,上层依赖于下层,当下层发生重大变化时,上层也要跟着变动,这就会导致模块的复用性降低,大大提高了开发的成本。

  面向对象的开发很好地解决了这个问题,通过分离接口与实现,使得类与类、模块与模块之间只有依赖于接口,而不依赖于具体的实现类。在一般情况下,抽象的接口的变化概率是很小的,依赖接口而不依赖具体实现,即使实现细节不断变动,只要抽象不变,上层依赖就不需要改动。这大大降低了客户程序与实现细节的耦合度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大白有点菜

你的鼓励决定文章的质量

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值