开发语言中关于面向对象和面向过程的笔记
开发语言中关于面向对象和面向过程的笔记
- 市面主流语言分类
- 面向过程
- 面向对象
市面主流语言分类
- 面向过程编程(Procedural Programming):C语言;
- 面向对象编程语言(Object-Oriented Programming, OOP) :Java、C++、C#、Python;
面向过程
面向过程的程序可以视为一系列线性执行的步骤(函数或子程序),通过控制流语句(顺序、循环、分支)组织逻辑。
其中,
1、面向过程的变成语言数据和操作是分离的,数据是存储在变量中的,函数独立操作这些数据。
也就是定义的子函数与变量是相互独立的,通过函数调用传递数据。
例如,先定义不同功能的函数,然后在主函数中调用该子函数,子函数的入参在主函数中定义。
#include <stdio.h>// 定义独立函数操作数据
float circle_area(float radius) {return 3.14 * radius * radius;
}float rectangle_area(float width, float height) {return width * height;
}int main() {// 数据与函数分离float r = 5.0;float w = 4.0, h = 6.0;printf("Circle Area: %.2f\n", circle_area(r)); // 输出 78.50printf("Rectangle Area: %.2f\n", rectangle_area(w, h)); // 输出 24.00return 0;
}
面向过程的变成方法,都是从主函数开始,逐步分解任务为子过程,也就是自顶向下设计
所以,面向过程的变成的基本单元是函数(过程)
面向过程是步骤导向
面向对象
面向对象的程序由相互作用的对象构成,每个对象包含数据(属性)和行为(方法)。
// 这里定义了一个类Circle,在这个类里封装了一个变量radius和一个行为(方法)getArea。
class Circle { private double radius; // 半径被保护 【这里的变量是private,意味着这是一个私有变量,私有意味着只能在Circle类内部访问,外部无法直接访问。所以称为“半径被保护”,这里的面向对象封装起到了数据保护的作用】//我们将半径设为私有,这样外部代码不能直接修改半径(除非通过构造方法,但构造方法只在创建对象时调用一次)public Circle(double r) { this.radius = r;this.radius = r; } //【这里是一个公共的构造方法,这个方法的参数是r,用于在创建Circle对象时初始化半径(创建Circle类的对象)。通过这个公共方法的参数r,将r的值传递给成员变量radius,//这里的this是指当前对象,也就是使用类创建对象后,这个对象就有个这个变量,通过构造函数对这个变量进行赋值。】//【先定义类,然后类中定义构造函数,构造函数用于定义新的方法,方法通过构造函数对变量进行赋值,然后再使用定义的对象调用类中的方法】public double getArea() { // 对象自己计算【公共方法,无参数】 ,这里是行为封装 ,逻辑封装在内部,外部只需要调用该方法return 3.14 * radius * radius; }
} // 这里使用 Circle 类创建了对象myCircle
Circle myCircle = new Circle(5.0); //【new用来创建新的对象,这里使用构造方法Circle,将5.0传递给了r。创建的对象被赋值给了Circle 类型的变量myCircle 】
//【这里需要注意,在这里进行对象初始化时即确定半径值,后续无法直接修改,如果要修改需要创建setRadius 方法】
//对象的创建步骤为:1、new 在堆内存分配空间,创建 Circle 对象实例。2、调用构造方法 Circle(5.0),初始化 radius = 5.0。3、对象地址赋值给引用变量 myCircle(栈内存存储该地址)。double area = myCircle.getArea(); // 告诉圆:"把你的面积给我"【这里的myCircle 是个对象,通过对象调用了类中的方法getArea】
//【这个例子展示了面向对象编程中的**封装特性**:将数据(半径)隐藏在对象内部,通过公共方法提供对数据的操作(计算面积)。外部代码只需要知道如何调用方法,而不需要知道内部实现细节。】
在这个例子中,定义了类Circle ,在类中定义了一个私有成员变量radius,一个构造方法Circle,一个成员方法getArea。
**【堆与栈需单独分析】**
总结面向对象的编程
类是较为顶层的设计,在类中定义各种成员,通过类定义这个类的对象。
上面例子中,通过私有的变量+公有的方法,仅暴漏接口,保障了数据的安全性,私有变量只有创建方法时定义,通过构造函数。
通俗的理解:
面向过程:是厨师,自己按步骤做菜。
第1步:拿2个番茄切块
第2步:打3个鸡蛋搅匀
第3步:开火倒油,炒鸡蛋后盛出
第4步:炒番茄,加鸡蛋混合
第5步:放盐出锅
面向对象:是餐厅老板,开一家餐厅
招专业员工(创建对象):
🧑🍳 厨师对象:技能 炒菜()
🧅 番茄对象:属性「颜色=红」,行为「被切块」
🥚 鸡蛋对象:属性「数量=3」,行为「被打散」
发号施令(对象交互)
厨师.处理(番茄); // 番茄自己执行"切块"
厨师.处理(鸡蛋); // 鸡蛋自己执行"打散"
厨师.炒(番茄, 鸡蛋); // 厨师调用"炒"方法
最后再做一次分析
// 抽象父类:定义公共接口
//定义抽象类Shape,抽象类不可实例化,也就不不能创建对象
//通过抽象类定义了一个模版,一个形状的模版(也可以是一个汽车的模版)
abstract class Shape {public abstract double area();//抽象类中定义抽象方法,这个方法在子类中必须被实现
}// 子类继承并实现多态
class Circle extends Shape {//子类Circle 继承了父类Shape ,因为Shape中包含抽象方法,因此在这个子类中必须实现该方法,也就是必须包含方法体
//一个普通类继承“形状”这个抽象类,定义了一个圆形,该类包含了圆形的具体实现,根据抽象类的要求,必须实现该形状的面积。private double radius; // 封装数据。封装私有成员变量public Circle(double radius) {//构造函数this.radius = radius;}@Override//重写父类的方法area,可用户后续的多态实现,需要使用哪个便创建哪个子类的对象,结果将根据子类的不同而不同public double area() { // 多态实现。对继承的父类中的抽象方法进行实现。return Math.PI * radius * radius;}//方法体
}class Rectangle extends Shape {//同理,这是定义了一个长方形类,该类继承了抽象类“形状”,因此在这个长方形中“面积”这个方法必须被实现private double width, height;//定义私有成员变量public Rectangle(double width, double height) {//长方形这个类的构造函数this.width = width;this.height = height;}@Overridepublic double area() {//实现抽象方法“面积”return width * height;}
}public class Main {//定义一个公有的类Mainpublic static void main(String[] args) {//定义了main方法Shape circle = new Circle(5.0); // 父类引用指向子类对象。创建了一个对象circle ,这里的构造函数Circle引用了父类Shape的子类Circle Shape rect = new Rectangle(4.0, 6.0);//同理,再创建一个对象rect,引用了子类//多态:通过父类引用调用子类重写的方法,实际执行的是子类的方法。 System.out.println("Circle Area: " + circle.area()); // 78.54。打印对象circle的方法areaSystem.out.println("Rectangle Area: " + rect.area()); // 24.00}
}
面向对象的编程的基本单元是对象(数据 + 方法)
面向对象是角色协作
上面通过对实际代码的解析,尝试理解java的面向对象开发,对于某一个任务可以通过定义类来定义功能,后续可以直接通过构造函数创建该类的对象,对象通过调用具体方法来完成对单功能的实现。
也可以其他类通过创建该类的对象,通过构造函数,然后调用该对象中的方法,以实现具体目标
例如,这边通过多单元分工实现了多个功能类的开发,开发完成后统一由一个人创建一个类来创建各个类的对象,通过该对象调用方法达到实现某功能的目标。
也就是面向对象的编程。
整体上看,面向过程的编程更适合单体作战,一个人完成重头到尾的任务。面向过程的编程更适合集群作战,每个角色负责不同的任务,通过多体交互完成最终任务。