引言
面向对象程序设计(Object Oriented Programming)作为一种程序设计方法,其本质是建立模型所反映的抽象思维过程。该模型用于反映现实世界中事物的特征。任何模型都不能反映客观事物的所有具体特征。它只能是对事物特征和变化规律的抽象,在其范围内更加普遍、集中和深刻地描述对象的特征。本场 Chat 在中国,我们将介绍程序设计的方法、面向对象程序设计的编程机制以及我们如何使用它 Java 这种语言对象编程,提高面向对象编程开发能力。目前,主流程序设计方法主要分为两种,一种是面对过程的程序设计方法,另一种是面向对象的程序设计方法。
面向过程的编程机制和得失
编程机制是我们首先要考虑程序应该实现什么样的功能。然后,设计实现此功能所需的步骤是一个过程。编程机制侧重于如何实现过程。当我们使用面向过程的程序设计方法来编写程序时,程序结构是数据 + 算法是解决问题的步骤。过程程序设计支持逐步改进的程序开发方法,这对实现复杂算法具有重要的启发性。对于复杂算法,我们不是一次详细写下它的所有实现细节,而是从基本算法框架开始,逐步实现细节。
“数据 + 算法的程序结构适用于中小型程序,一般代码长度为 1 如果我们的程序想要更多的功能,我们必须定义新的函数并添加新的代码。当代码量超过时 1 在一定程度上,面向过程的程序设计方法暴露了它的缺点。
– 第一个缺点是程序代码不易维护。如果程序的数据结构发生变化,则需要相应修改操作数据结构的函数。如果数据结构被许多函数访问,则需要修改这些函数,因此工作量很大,因此代码不易维护。
第二个缺点是代码重用效率不高。只有函数的代码被重用,保存数据变量的代码没有重用,因此代码的重用效率不高。第三个缺点是数据安全得不到保证。开发团队成员定义的变量可能会被其成员编写的方法访问和修改。这样,当程序运行时,变量值可能会意外修改,因此无法保证数据安全。
在这些问题中,最严重的是数据安全问题,因为数据安全得不到保证,可能会直接导致程序无法正确执行。
模拟面向过程的程序设计方法 ATM 自动取款机的工作流程
下列代码包括一个主过程 main() 和 8 个子过程,在主过程中调用子过程,程序没有模拟用户账户的对象,所以取款后,程序没有从账户中扣除取款金额。
import java.util.Scanner;\public class SimulateATM { public static void main(String[] args) { int total = 5000; ATM atm = new ATM(); int select; ///用户输入服务 atm.welcome(); //显示欢迎信息 atm.pass(); //进行密码验证 do { select = atm.service(); atm.selectService(select,total); }while(true); } void welcome() { System.out.println("——————ATM 自动取款系统——————–"); System.out.println(";请输入您的磁卡(按任何按钮完成)"); } void pass() { int n,password; Scanner in = new Scanner(System.in); for(n=1;n<=3;n++) { if(n==1) { System.out.println(" 3 次)!"); }else { System.out.println(";密码错误,请重新输入!"); } password = in.nextInt(); if(password==123) { break; } if(n>3) { System.out.println(";遇到问题,请联系银行管理员"); System.exit(1); } } } int service() { int select; Scanner in = new Scanner(System.in); System.out.println("\*******************欢迎进入银行自动取款系统******************\"); System.out.println("\*******************您选择的服务是******************\"); System.out.println(" 查询余额-1\"); System.out.println(" 取款——2\"); System.out.println(" 快速取款-3\"); System.out.println(" 取卡——0\"); System.out.println("——————————————————-\"); System.out.println(";请输入选择:"); select = in.nextInt(); return select; } void selectMoney(int a){ System.out.println("\\\ 你账户上的余额是"+a+"元\\\"); } void getMoney(int total) { int number; int flag; Scanner in = new Scanner(System.in); System.out.println(";请输入取款金额:"); number = in.nextInt(); if(total>=number) { total = total – number; System.out.println(";请取现金。"+number+"元\"); System.out.println(";需要打印凭证(1/0)吗?"); flag = in.nextInt(); if(flag == 1) { System.out.println("您取款"+number+"元"); } }else { System.out.println(";您的余额不足!"); } } void quickGetMoney(int total) { Scanner in = new Scanner(System.in); int select,number=0; String flag; System.out.println("\\————-请选择取款金额\"); System.out.println("\\100(1)\\200(2)\\\500(3)\\1000(4)\"); select = in.nextInt(); switch(select) { case 1:number=100;break; case 2:number=200;break; case 3:number=500;break; case 4:number=1000;break; } if(total >= number) { System.out.println(";请取现金。"+number+"元\"); total = total – number; System.out.println(";需要打印凭证吗?(Y/N)?"); flag = in.next(); if("Y".equals(flag)) { System.out.println("您取款"+number+"元"); } }else { System.out.println(";您的余额不足!"); } } void exitATM() { System.out.println(";请拿走你的磁卡,谢谢,欢迎下次光临!\"); System.exit(1); } void selectService(int select,int total) { switch(select) {n case 1:selectMoney(total);break;n case 2:getMoney(total);break;n case 3:quickGetMoney(total);break;n case 0:exitATM();n default:System.out.println("非法操作!");n }n }n}n面向对象的程序设计方法
为了解决面向过程的程序设计方法暴露的问题,人们就提出了面向对象的程序设计方法,我们说一门编程语言是面向对象的程序设计语言,那就意味着这门语言是支持面向对象程序设计方法的。所以,学习这门语言关键就是理解面向对象的程序设计方法,掌握它的编程机制。
在讲解之前,我们先了解一下什么是面向对象?面向对象是一种解决问题的方法和观点,它认为现实世界是由一组彼此相关,并且能够相互通信的实体所组成。比如教室里的课桌,电脑都是实体。一个事物在现实世界中,我们称它为实体,在由计算机软硬件所组成的信息系统中,我们称它为对象。现实世界中的实体都有属性和行为,我们程序中的对象,相应的也有属性和行为。比如一块手表,它有属性时、分、秒,用来代表当前时间,它有行为显示时间、设置时间,代表它做具有的功能。
面向对象的程序设计方法的编程机制及得失
了解了面向对象的概念之后,我们再进一步学习面向对象的编程机制。面向对象的程序设计,它的编程机制是,我们首先考虑要实现什么样的功能,然后设计实现这个功能所需要的对象和对象之间是如何发送消息相互驱动的。面向对象的程序设计它的编程机制关注的是对象和对象之间的关系。
当我们采用面向对象的程序设计方法,编写程序的时候,得到的程序结构是“对象+消息”。简单的说,编程就是用计算所需的指令来构成一种运算装置。对象在操作上是一种能响应消息的抽象的机器。这种方法的优点是,它更符合人的思维方式,面向对象的程序设计语言更容易被学习者掌握,编写的程序更容易维护。更重要的是“对象+消息”的程序结构可以有效的保证数据的安全。
面向对象系统中的计算是指对象间相互发送消息,这可能导致非常复杂的指令序列,为了控制这种复杂性我们需要考虑如何组织对象,我们需要一个定义和协调对象间交互的软件体系结构。面向对象方法使程序开发有了很大的灵活性,但他仍然存在一些固有的本身机制难以解决的问题,面向对象库和框架的设计经验表明用对象构建的模块结构有时是不稳定的。因此,面向对象的真正长处可能要打一些折扣。另外面向对象的程序设计还需要克服以下两个缺点。
第一个缺点,虽然继承性提高了代码的可复用性,但由于基类的信息隐藏,只阅读子类的代码,往往不足以很好的理解它。
第二个缺点,如果把开发的重点放在软件设计阶段,而不是编程实现阶段,就比较容易建立起稳定的模块化结构,采用面向对象程序设计,程序员可以自然而直接的,直接地对应用系统建模,但这要以提高设计阶段的投资为代价。
面向对象程序设计的四个基本机制:抽象、封装、继承、多态
采用面向对象程序设计方法之所以有这么多的好处,是通过面向对象的编程机制来实现的,下面我们来进一步讲解面向对象的编程机制。面向对象的程序设计,包括四个基本机制:抽象、封装、继承、多态。
抽象
抽象就是找共性,现实世界中的实体都有属性和行为,我们把具有相同属性名和行为名的实体归为一类,就得到了类型,类型和类是同一个概念,类型的定义就是类的定义。我们根据类型创建对象,类就相当于是对象的设计图纸,对象是类的实例。我们编写程序首先要定义类,然后根据类的定义创建对象,使用对象。
自然语言有语法规则,计算机编程语言也有语法规则。我们必须按照规定的语法格式来编写程序,这样的程序才能够在计算机上执行,定义一个类的语法格式,类的定义包含两部分:类头、类体。
类头由关键字 class 以及后面的类名构成。类体是一个代码块。类体的里面定义了类的成员,类的成员包括数据成员和成员函数,类的数据成员代表对象具有的属性,成员函数代表对象具有的行为,我们在类体中对数据成员和成员函数进行声明,数据成员的声明方式和变量的声明方式相同,成员函数的声明方式和函数的声明方式相同。
下面我们来看一个例子,我们在这里定义了一个学生类,学生类是对学生实体的抽象,因此需要了解学生对象有哪些特征,可知每个学生都有身份证号、学号、姓名、年龄以及性别等信息,因此在学生类中就要对学生这些共同特征进行抽象。
public class Student//类名n{n String id;//身份证号码 n String name; //姓名n int age;//年龄n String sex;//性别n String sno;//学号n}npublic class TestStudent{n public static void main(String [] args){n //创建学生对象,对象名小明n Student xiaoming = new Student ();n }n}npublic class StudentWithMethod {n String id;//身份证号码 n String name; //姓名n int age;//年龄n String sex;//性别n String sno;//学号n public void study( ){n System.out.println("我是"+name+",我在好好学习");n }n}n封装
封装是对象支持的信息隐藏,打包和隐藏两者的结合就称为封装。对象在结构上可以看成是数据和方法的集合,原则上数据对外是不可见的,只能通过调用过程本身对其进行操作调用,这样的过程的唯一途径就是向对象发送消息数据隐藏。和消息接口抽象结合在一起被称为封装。事实上,在面向对象语言中,对象都是数据和过程的结合,只是对数据隐藏和抽象的程度和方式有所不同,方法提供服务,消息是执行方法的请求。
使用对象时,客户程序只需要知道对象能做什么,而不需要知道对象是如何做的,然而要体现出对象数据隐藏的优势对象的开发者必须提供一个能够以充分抽象的方式表现对象行为的接口,这种设计思想把对象看成是一个能响应高层请求的服务器,同时还要决定应用程序需要对象提供何种服务。
对象实现封装后,对象成员的可见范围,可以通过类定义中成员声明前的访问控制修饰确定,访问控制修饰符及其被修饰成员的可见范围如下所示:
示例代码如下:
package cn.edu.lyu.info.test1;n//理解访问修饰符npublic class AccessModifier {n private int a;// 私有整型变量 an int b;// 缺省的整型变量n protected int c;//受保护变量 cn public int d;//公有的变量 dn public AccessModifier() {n super();n a = 1;n b = 2;n c = 3;n d = 4;n }n}nnpackage cn.edu.lyu.info.test1;npublic class AccessModifierTest {n //测试同包中访问修饰符类各种访问修饰符的权限 n public static void main(String[] args) {n AccessModifier modifier = new AccessModifier();n //modifier.a = 4;//error 私有成员变量 a 的类外无法访问n modifier.b = 6;//正确 缺省的成员变量 b 在同包内可以访问n modifier.c = 8;//正确 受保护的成员变量 c 在同包内可以访问n modifier.d = 10;//正确,公有的成员变量 d 在同包内可以访问n }n}nnpackage cn.edu.lyu.info.test2;n//导入包中的类nimport cn.edu.lyu.info.test1.AccessModifier;npublic class AccessModifierTest1 {n //测试其他包中访问修饰符类各种访问修饰符的权限n public static void main(String[] args) {n AccessModifier modifier = new AccessModifier();n //modifier.a =4;//error 私有成员变量 a 的类外无法访问n //modifier.b = 6;//error 缺省成员变量 b 在其他包内不能访问n //modifier.c = 8;//error 受保护成员变量 c 在其他包内不能访问n modifier.d = 10;//正确,公有的成员变量 d 在其他包内可以访问n }n}n继承
继承是提供可复用性的主要机制,因为复用的代码往往不能满足全部需求,这时继承机制,使程序员可以修改对象类的行为,而无需访问源代码。对象按类进行划分,类定义了对象的行为,也可以把类看成创建对象的模板,具有继承性,从设计的角度看,继承机制主要用于提高类的可复用度。类的层次结构是表示类的继承关系的树结构,继承的语法格式如下所示:
访问控制修饰符 子类名 extends 父类名{n //子类类体n}n
Java 中的继承关系是单继承关系,子类只能有一个父类,即 extends 后面的父类只能有一个。
例如:动物类定义属性动物的名称,体重,同时所有的动物都有吃、运动的行为,因此定义 eat 方法和 run 方法。老虎类继承动物类,因此继承相关的属性和方法,同时老虎有自己的新特性,狩猎,因此在老虎类有新方法 hunt。
public class Animal {//定义动物类n protected String name;//定义变量 namen public void run(){n System.out.println("动物可以运动…");n }n public void eat(){n System.out.println("动物需要吃东西…");n }n public Animal(String name) {n super();n this.name = name;n }n public Animal() {n name = "未知";n }n }nn//extends 继承动物类,生成老虎类npublic class Tiger extends Animal{n public void hunt(){// 添加新方法 狩猎n System.out.println("老虎可以凶猛的狩猎");n }n}nnpackage cn.edu.lyu.info.inherit;npublic class TigerTest {n public static void main(String[] args) {n //测试老虎类拥有的方法n Tiger tiger = new Tiger();n tiger.setName("老虎");//调用父类方法,设置 name 属性n tiger.eat();//调用父类方法n tiger.run();//调用父类方法n tiger.hunt();//调用子类新加方法n }n}n多态
多态的定义:多态是指对象在调用同一个函数时所呈现的多种不同的行为。
补充说明:同一个函数意味着函数名相同,不同的行为意味着函数体不同。
多态的实现:
编译时多态:函数的重载运行时多态:函数的重写
函数的重载
问题的提出:函数名数量巨大,管理困难。解决方案:功能相近的函数进行合并。
例如下列代码中,将类 Examle05 中的函数 add01、add02、add03 合并为类 Examle06 中的 add 函数。
public class Example01{n public int add01(int x, int y){n return x + y;n }n public int add02(int x, int y,int z){n return x + y + z;n }n public double add03(double x, double y){n return x + y;n }n public static void main(String[] args ){n Example01 example01 = new Example01();n int sum1 = example01.add01(1,2);n int sum2 = example01.add02(3,4,7);n double sum3 = example01.add03(0.2,5.3);n System.out.println("sum1="+sum1);n System.out.println("sum2="+sum2);n System.out.println("sum3="+sum3);n }n}n//当定义函数时,存在多个具有相同函数名的函数,但具有不同函数列表的函数,则意味着该函数被重载。npublic class Example02{n public int add(int x, int y){n return x + y;n }n public int add(int x, int y,int z){n return x + y + z;n }n public double add(double x, double y){n return x + y;n }n public static void main(String[] args ){n Example02 example02 = new Example02();n int sum1 = example02.add(1,2);n int sum2 = example02.add(3,4,7);n double sum3 = example02.add(0.2,5.3);n System.out.println("sum1="+sum1);n System.out.println("sum2="+sum2);n System.out.println("sum3="+sum3);n }n}n
使用重载时需要注意的规则如下所示:
被重载的函数必须改变参数列表;被重载的函数可以改变返回类型;被重载的函数可以改变访问控制修饰符;被重载的函数可以声明新的或更广的检查异常;函数能够在同一个类中或者再一个子类中被重载。
注意:第 2 条和第 3 条规则也可以表述为,函数的返回类型、修饰符与函数重载无关,函数的返回类型、修饰符可以相同,也可不同。
函数的重写
子类重写从父类继承的函数,重写表示重写继承函数的函数体的语句,而不是改变函数首部,这与函数的重载不同。子类重写的函数的访问权限不能低于父类函数的访问权限,例如父类函数使用 public 修饰,那么子类重写函数只能使用 public 修饰,当子类对象调用重写的函数时,调用子类重写后的函数。
例如:Tiger 类继承 Animal 的类的 walk 和 eat 函数,但 Animal 类的 walk 和 eat 函数不适合 Tiger 类,因此要重写两个函数的方法体。
package cn.edu.lyu.info.inherit;npublic class Tiger extends Animal {n //Tiger 继承 Animal 并函数重写n public void run() {// 重写父类函数 run,重写函数体n System.out.println("老虎用四肢跑步,跑的飞快");n }n // 注解表示该函数为重写父类函数n public void eat() {// 重写父类函数 eatn System.out.println("老虎是肉食动物,凶猛的吃肉");n }n public void hunt() {n System.out.println("老虎可以凶猛的狩猎");n }n}nnpackage cn.edu.lyu.info.inherit;npublic class TestTiger {n public static void main(String[] args) {//n TigerOverride tiger = new TigerOverride();n tiger.setName("老虎");n //调用父类函数,设置 name 属性n tiger.eat();n //调用子类重写父类的函数n tiger.run();n //调用子类重写父类的函数n tiger.hunt();//调用子类新加函数n }n}n
总而言之,多态性是隐藏公用接口的不同实现,对象灵活的分配行为使对象具有多态性,这得益于方法和消息的动态绑定。类的继承导致了类的层次结构,从操作的角度看,这种结构决定了对象的分配行为,即对于某一消息选用哪个方法来处理。
采用面向对象的程序设计方法模拟 ATM 自动取款机的工作流程
程序源代码包括 ATM.java 和 TestATM.java 两个文件。
源代码文件 ATM.java 的内容如下:
import java.util.Scanner;npublic class ATM {n Scanner in = new Scanner(System.in);n void welcome() {n System.out.println("——————ATM 自动取款系统——————–");n System.out.println("请输入您的磁卡(按任意键完成)");n }n void pass() {n int n,password;n for(n=1;n<=3;n++) {n if(n==1) {n System.out.println("请输入密码(最多可输入 3 次)!");n }else {n System.out.println("密码错误,请重新输入!");n }n password = in.nextInt();n if(password==123) {n break;n }n if(n>3) {n System.out.println("遇到问题,请与银行管理员联系");n System.exit(1);n }n }n }n int service() {n int select;n System.out.println("*******************欢迎进入银行自动取款系统******************");n System.out.println("*******************您选择的服务是******************");n System.out.println(" 查询余额——1");n System.out.println(" 取款——2");n System.out.println(" 快速取款——3");n System.out.println(" 取卡——0");n System.out.println("——————————————————-");n System.out.println("请输入选择:");n select = in.nextInt();n return select;n }n void selectMoney(int a){n System.out.println(" 您账户上的余额为"+a+"元");n }n void getMoney(int total) {n int number;n int flag;n System.out.println("请输入取款金额:");n number = in.nextInt();n if(total>=number) {n total = total – number;n System.out.println("请取走您的现金"+number+"元");n System.out.println("是否需要打印凭证(1/0)?");n flag = in.nextInt();n if(flag == 1) {n System.out.println("您取款"+number+"元"); n }n }else {n System.out.println("您的余额不足!");n }n }n void quickGetMoney(int total) {n int select,number=0;n String flag;n System.out.println("————-请选择取款金额");n System.out.println("100(1)200(2)500(3)1000(4)");n select = in.nextInt();n switch(select) {n case 1:number=100;break;n case 2:number=200;break;n case 3:number=500;break;n case 4:number=1000;break;n }n if(total >= number) {n System.out.println("请取走您的现金"+number+"元");n total = total – number;n System.out.println("是否需要打印凭证(Y/N)?");n flag = in.next();n if("Y".equals(flag)) {n System.out.println("您取款"+number+"元"); n }n }else {n System.out.println("您的余额不足!");n }n }n void exitATM() {n System.out.println("请取走您的磁卡,谢谢,欢迎下次光临!");n System.exit(1);n }n void selectService(int select,int total) {n switch(select) {n case 1:selectMoney(total);break;n case 2:getMoney(total);break;n case 3:quickGetMoney(total);break;n case 0:exitATM();n default:System.out.println("非法操作!");n }n }n}nn//源代码文件 TestATM.java 的内容如下:npublic class TestATM {n public static void main(String[] args) {n int total = 5000;n ATM atm = new ATM();n int select; //用户输入的服务n atm.welcome(); //显示欢迎信息n atm.pass(); //进行密码验证n do {n select = atm.service();n atm.selectService(select,total);n }while(true);n }n}n总结
面向对象的程序设计方法,其本质是强调从客观世界固有的事物出发来构造系统,用人类习惯的思维方式来认识理解和描述客观事物,强调最终建立的软件系统能够映射问题域软件系统中的对象和对象之间的关系,能够如实的反映问题域中的事物及其关系,面向对象对于复杂软件系统的分析设计实现与测试向软件开发人员提供了正确的抽象。
把对象作为软件分析、设计和实现的基本单元,使我们可以以一种自然的方式定义整个软件系统的结构和行为。面向对象编程并没有扩大可计算问题的类型,也不能降低我们能够处理的问题的计算复杂性。我们不能期望解决更多的问题,也不能期望减少运算的复杂性,但是面向对象方法能提供更好的方式来编程更好的方式来减少错误以及更好的方式来控制编程任务的复杂性,不是计算本身的复杂性,换句话说。通过更多的面向人而更少的面向机器的抽象机制,面向对象使我们在实际软件开发中能处理更多的问题。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至827202335@qq.com 举报,一经查实,本站将立刻删除。文章链接:https://www.eztwang.com/dongtai/65212.html