引言
面向對象程序設計(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("n*******************歡迎進入銀行自動取款系統******************n");
System.out.println("n*******************您選擇的服務是******************n");
System.out.println(" 查詢余額——1n");
System.out.println(" 取款——2n");
System.out.println(" 快速取款——3n");
System.out.println(" 取卡——0n");
System.out.println("-------------------------------------------------------n");
System.out.println("請輸入選擇:");
select = in.nextInt();
return select;
}
void selectMoney(int a){
System.out.println("nn 您賬戶上的余額為"+a+"元nn");
}
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+"元n");
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("tt-------------請選擇取款金額n");
System.out.println("tt100(1)tt200(2)ntt500(3)tt1000(4)n");
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+"元n");
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("請取走您的磁卡,謝謝,歡迎下次光臨!n");
System.exit(1);
}
void selectService(int select,int total) {
switch(select) {
case 1:selectMoney(total);break;
case 2:getMoney(total);break;
case 3:quickGetMoney(total);break;
case 0:exitATM();
default:System.out.println("非法操作!");
}
}
}
面向對象的程序設計方法
?為了解決面向過程的程序設計方法暴露的問題,人們就提出了面向對象的程序設計方法,我們說一門編程語言是面向對象的程序設計語言,那就意味著這門語言是支持面向對象程序設計方法的。所以,學習這門語言關鍵就是理解面向對象的程序設計方法,掌握它的編程機制。
?在講解之前,我們先了解一下什么是面向對象?面向對象是一種解決問題的方法和觀點,它認為現實世界是由一組彼此相關,并且能夠相互通信的實體所組成。比如教室里的課桌,電腦都是實體。一個事物在現實世界中,我們稱它為實體,在由計算機軟硬件所組成的信息系統中,我們稱它為對象?,F實世界中的實體都有屬性和行為,我們程序中的對象,相應的也有屬性和行為。比如一塊手表,它有屬性時、分、秒,用來代表當前時間,它有行為顯示時間、設置時間,代表它做具有的功能。


面向對象的程序設計方法的編程機制及得失
?了解了面向對象的概念之后,我們再進一步學習面向對象的編程機制。面向對象的程序設計,它的編程機制是,我們首先考慮要實現什么樣的功能,然后設計實現這個功能所需要的對象和對象之間是如何發送消息相互驅動的。面向對象的程序設計它的編程機制關注的是對象和對象之間的關系。
?當我們采用面向對象的程序設計方法,編寫程序的時候,得到的程序結構是“對象+消息”。簡單的說,編程就是用計算所需的指令來構成一種運算裝置。對象在操作上是一種能響應消息的抽象的機器。這種方法的優點是,它更符合人的思維方式,面向對象的程序設計語言更容易被學習者掌握,編寫的程序更容易維護。更重要的是“對象+消息”的程序結構可以有效的保證數據的安全。
?面向對象系統中的計算是指對象間相互發送消息,這可能導致非常復雜的指令序列,為了控制這種復雜性我們需要考慮如何組織對象,我們需要一個定義和協調對象間交互的軟件體系結構。面向對象方法使程序開發有了很大的靈活性,但他仍然存在一些固有的本身機制難以解決的問題,面向對象庫和框架的設計經驗表明用對象構建的模塊結構有時是不穩定的。因此,面向對象的真正長處可能要打一些折扣。另外面向對象的程序設計還需要克服以下兩個缺點。
?第一個缺點,雖然繼承性提高了代碼的可復用性,但由于基類的信息隱藏,只閱讀子類的代碼,往往不足以很好的理解它。
第二個缺點,如果把開發的重點放在軟件設計階段,而不是編程實現階段,就比較容易建立起穩定的模塊化結構,采用面向對象程序設計,程序員可以自然而直接的,直接地對應用系統建模,但這要以提高設計階段的投資為代價。
面向對象程序設計的四個基本機制:抽象、封裝、繼承、多態
?采用面向對象程序設計方法之所以有這么多的好處,是通過面向對象的編程機制來實現的,下面我們來進一步講解面向對象的編程機制。面向對象的程序設計,包括四個基本機制:抽象、封裝、繼承、多態。
抽象
?抽象就是找共性,現實世界中的實體都有屬性和行為,我們把具有相同屬性名和行為名的實體歸為一類,就得到了類型,類型和類是同一個概念,類型的定義就是類的定義。我們根據類型創建對象,類就相當于是對象的設計圖紙,對象是類的實例。我們編寫程序首先要定義類,然后根據類的定義創建對象,使用對象。


自然語言有語法規則,計算機編程語言也有語法規則。我們必須按照規定的語法格式來編寫程序,這樣的程序才能夠在計算機上執行,定義一個類的語法格式,類的定義包含兩部分:類頭、類體。
?類頭由關鍵字 class 以及后面的類名構成。類體是一個代碼塊。類體的里面定義了類的成員,類的成員包括數據成員和成員函數,類的數據成員代表對象具有的屬性,成員函數代表對象具有的行為,我們在類體中對數據成員和成員函數進行聲明,數據成員的聲明方式和變量的聲明方式相同,成員函數的聲明方式和函數的聲明方式相同。
下面我們來看一個例子,我們在這里定義了一個學生類,學生類是對學生實體的抽象,因此需要了解學生對象有哪些特征,可知每個學生都有身份證號、學號、姓名、年齡以及性別等信息,因此在學生類中就要對學生這些共同特征進行抽象。
public class Student//類名
{
? String id;//身份證號碼
? String name; //姓名
? int age;//年齡
? String sex;//性別
? String sno;//學號
}
public class TestStudent{
? public static void main(String [] args){
? //創建學生對象,對象名小明
Student xiaoming = new Student ();
? }
}
public class StudentWithMethod {
String id;//身份證號碼
? String name; //姓名
? int age;//年齡
? String sex;//性別
? String sno;//學號
? public void study( ){
? System.out.println("我是"+name+",我在好好學習");
? }
}
封裝
?封裝是對象支持的信息隱藏,打包和隱藏兩者的結合就稱為封裝。對象在結構上可以看成是數據和方法的集合,原則上數據對外是不可見的,只能通過調用過程本身對其進行操作調用,這樣的過程的唯一途徑就是向對象發送消息數據隱藏。和消息接口抽象結合在一起被稱為封裝。事實上,在面向對象語言中,對象都是數據和過程的結合,只是對數據隱藏和抽象的程度和方式有所不同,方法提供服務,消息是執行方法的請求。
?使用對象時,客戶程序只需要知道對象能做什么,而不需要知道對象是如何做的,然而要體現出對象數據隱藏的優勢對象的開發者必須提供一個能夠以充分抽象的方式表現對象行為的接口,這種設計思想把對象看成是一個能響應高層請求的服務器,同時還要決定應用程序需要對象提供何種服務。
?對象實現封裝后,對象成員的可見范圍,可以通過類定義中成員聲明前的訪問控制修飾確定,訪問控制修飾符及其被修飾成員的可見范圍如下所示:


示例代碼如下:
package cn.edu.lyu.info.test1;
//理解訪問修飾符
public class AccessModifier {
private int a;// 私有整型變量 a
? int b;// 缺省的整型變量
protected int c;//受保護變量 c
? public int d;//公有的變量 d
? public AccessModifier() {
? super();
? a = 1;
? b = 2;
? c = 3;
? d = 4;
? }
}
package cn.edu.lyu.info.test1;
public class AccessModifierTest {
//測試同包中訪問修飾符類各種訪問修飾符的權限
? public static void main(String[] args) {
? AccessModifier modifier = new AccessModifier();
? //modifier.a = 4;//error 私有成員變量 a 的類外無法訪問
modifier.b = 6;//正確 缺省的成員變量 b 在同包內可以訪問
? modifier.c = 8;//正確 受保護的成員變量 c 在同包內可以訪問
modifier.d = 10;//正確,公有的成員變量 d 在同包內可以訪問
? }
}
package cn.edu.lyu.info.test2;
//導入包中的類
import cn.edu.lyu.info.test1.AccessModifier;
public class AccessModifierTest1 {
? //測試其他包中訪問修飾符類各種訪問修飾符的權限
? public static void main(String[] args) {
? AccessModifier modifier = new AccessModifier();
? //modifier.a =4;//error 私有成員變量 a 的類外無法訪問
? //modifier.b = 6;//error 缺省成員變量 b 在其他包內不能訪問
? //modifier.c = 8;//error 受保護成員變量 c 在其他包內不能訪問
? modifier.d = 10;//正確,公有的成員變量 d 在其他包內可以訪問
? }
}
繼承
?繼承是提供可復用性的主要機制,因為復用的代碼往往不能滿足全部需求,這時繼承機制,使程序員可以修改對象類的行為,而無需訪問源代碼。對象按類進行劃分,類定義了對象的行為,也可以把類看成創建對象的模板,具有繼承性,從設計的角度看,繼承機制主要用于提高類的可復用度。類的層次結構是表示類的繼承關系的樹結構,繼承的語法格式如下所示:
訪問控制修飾符 子類名 extends 父類名{
? //子類類體
}
Java 中的繼承關系是單繼承關系,子類只能有一個父類,即 extends 后面的父類只能有一個。
例如:動物類定義屬性動物的名稱,體重,同時所有的動物都有吃、運動的行為,因此定義 eat 方法和 run 方法。老虎類繼承動物類,因此繼承相關的屬性和方法,同時老虎有自己的新特性,狩獵,因此在老虎類有新方法 hunt。
public class Animal {//定義動物類
? protected String name;//定義變量 name
? public void run(){
? System.out.println("動物可以運動...");
? }
? public void eat(){
? System.out.println("動物需要吃東西...");
? }
? public Animal(String name) {
? super();
? this.name = name;
? }
? public Animal() {
? name = "未知";
? }
}
//extends 繼承動物類,生成老虎類
public class Tiger extends Animal{
? public void hunt(){// 添加新方法 狩獵
? System.out.println("老虎可以兇猛的狩獵");
? }
}
package cn.edu.lyu.info.inherit;
public class TigerTest {
? public static void main(String[] args) {
? //測試老虎類擁有的方法
? Tiger tiger = new Tiger();
? tiger.setName("老虎");//調用父類方法,設置 name 屬性
? tiger.eat();//調用父類方法
? tiger.run();//調用父類方法
? tiger.hunt();//調用子類新加方法
? }
}
多態
多態的定義:多態是指對象在調用同一個函數時所呈現的多種不同的行為。
補充說明:同一個函數意味著函數名相同,不同的行為意味著函數體不同。
多態的實現:
- 編譯時多態:函數的重載
- 運行時多態:函數的重寫
函數的重載
- 問題的提出:函數名數量巨大,管理困難。
- 解決方案:功能相近的函數進行合并。
例如下列代碼中,將類 Examle05 中的函數 add01、add02、add03 合并為類 Examle06 中的 add 函數。
public class Example01{
? public int add01(int x, int y){
? return x + y;
}
public int add02(int x, int y,int z){
? return x + y + z;
}
public double add03(double x, double y){
? return x + y;
}
public static void main(String[] args ){
? Example01 example01 = new Example01();
? int sum1 = example01.add01(1,2);
? int sum2 = example01.add02(3,4,7);
? double sum3 = example01.add03(0.2,5.3);
? System.out.println("sum1="+sum1);
? System.out.println("sum2="+sum2);
? System.out.println("sum3="+sum3);
}
}
//當定義函數時,存在多個具有相同函數名的函數,但具有不同函數列表的函數,則意味著該函數被重載。
public class Example02{
public int add(int x, int y){
? return x + y;
}
public int add(int x, int y,int z){
? return x + y + z;
}
public double add(double x, double y){
? return x + y;
}
public static void main(String[] args ){
? Example02 example02 = new Example02();
? int sum1 = example02.add(1,2);
? int sum2 = example02.add(3,4,7);
? double sum3 = example02.add(0.2,5.3);
? System.out.println("sum1="+sum1);
? System.out.println("sum2="+sum2);
? System.out.println("sum3="+sum3);
}
}
使用重載時需要注意的規則如下所示:
- 被重載的函數必須改變參數列表;
- 被重載的函數可以改變返回類型;
- 被重載的函數可以改變訪問控制修飾符;
- 被重載的函數可以聲明新的或更廣的檢查異常;
- 函數能夠在同一個類中或者再一個子類中被重載。
注意:第 2 條和第 3 條規則也可以表述為,函數的返回類型、修飾符與函數重載無關,函數的返回類型、修飾符可以相同,也可不同。
函數的重寫
子類重寫從父類繼承的函數,重寫表示重寫繼承函數的函數體的語句,而不是改變函數首部,這與函數的重載不同。子類重寫的函數的訪問權限不能低于父類函數的訪問權限,例如父類函數使用 public 修飾,那么子類重寫函數只能使用 public 修飾,當子類對象調用重寫的函數時,調用子類重寫后的函數。
例如:Tiger 類繼承 Animal 的類的 walk 和 eat 函數,但 Animal 類的 walk 和 eat 函數不適合 Tiger 類,因此要重寫兩個函數的方法體。
package cn.edu.lyu.info.inherit;
public class Tiger extends Animal {
? //Tiger 繼承 Animal 并函數重寫
? public void run() {// 重寫父類函數 run,重寫函數體
? System.out.println("老虎用四肢跑步,跑的飛快");
? }
? // 注解表示該函數為重寫父類函數
? public void eat() {// 重寫父類函數 eat
? System.out.println("老虎是肉食動物,兇猛的吃肉");
? }
? public void hunt() {
? System.out.println("老虎可以兇猛的狩獵");
? }
}
package cn.edu.lyu.info.inherit;
public class TestTiger {
? public static void main(String[] args) {//
? TigerOverride tiger = new TigerOverride();
? tiger.setName("老虎");
? //調用父類函數,設置 name 屬性
? tiger.eat();
//調用子類重寫父類的函數
? tiger.run();
? //調用子類重寫父類的函數
? tiger.hunt();//調用子類新加函數
? }
}
總而言之,多態性是隱藏公用接口的不同實現,對象靈活的分配行為使對象具有多態性,這得益于方法和消息的動態綁定。類的繼承導致了類的層次結構,從操作的角度看,這種結構決定了對象的分配行為,即對于某一消息選用哪個方法來處理。
采用面向對象的程序設計方法模擬 ATM 自動取款機的工作流程
程序源代碼包括 ATM.java 和 TestATM.java 兩個文件。
源代碼文件 ATM.java 的內容如下:
import java.util.Scanner;
public class ATM {
Scanner in = new Scanner(System.in);
void welcome() {
System.out.println("------------------ATM 自動取款系統--------------------");
System.out.println("請輸入您的磁卡(按任意鍵完成)");
}
void pass() {
int n,password;
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;
System.out.println("n*******************歡迎進入銀行自動取款系統******************n");
System.out.println("n*******************您選擇的服務是******************n");
System.out.println(" 查詢余額——1n");
System.out.println(" 取款——2n");
System.out.println(" 快速取款——3n");
System.out.println(" 取卡——0n");
System.out.println("-------------------------------------------------------n");
System.out.println("請輸入選擇:");
select = in.nextInt();
return select;
}
void selectMoney(int a){
System.out.println("nn 您賬戶上的余額為"+a+"元nn");
}
void getMoney(int total) {
int number;
int flag;
System.out.println("請輸入取款金額:");
number = in.nextInt();
if(total>=number) {
total = total - number;
System.out.println("請取走您的現金"+number+"元n");
System.out.println("是否需要打印憑證(1/0)?");
flag = in.nextInt();
if(flag == 1) {
System.out.println("您取款"+number+"元");
}
}else {
System.out.println("您的余額不足!");
}
}
void quickGetMoney(int total) {
int select,number=0;
String flag;
System.out.println("tt-------------請選擇取款金額n");
System.out.println("tt100(1)tt200(2)ntt500(3)tt1000(4)n");
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+"元n");
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("請取走您的磁卡,謝謝,歡迎下次光臨!n");
System.exit(1);
}
void selectService(int select,int total) {
switch(select) {
case 1:selectMoney(total);break;
case 2:getMoney(total);break;
case 3:quickGetMoney(total);break;
case 0:exitATM();
default:System.out.println("非法操作!");
}
}
}
//源代碼文件 TestATM.java 的內容如下:
public class TestATM {
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);
}
}
總結
?面向對象的程序設計方法,其本質是強調從客觀世界固有的事物出發來構造系統,用人類習慣的思維方式來認識理解和描述客觀事物,強調最終建立的軟件系統能夠映射問題域軟件系統中的對象和對象之間的關系,能夠如實的反映問題域中的事物及其關系,面向對象對于復雜軟件系統的分析設計實現與測試向軟件開發人員提供了正確的抽象。
把對象作為軟件分析、設計和實現的基本單元,使我們可以以一種自然的方式定義整個軟件系統的結構和行為。面向對象編程并沒有擴大可計算問題的類型,也不能降低我們能夠處理的問題的計算復雜性。我們不能期望解決更多的問題,也不能期望減少運算的復雜性,但是面向對象方法能提供更好的方式來編程更好的方式來減少錯誤以及更好的方式來控制編程任務的復雜性,不是計算本身的復雜性,換句話說。通過更多的面向人而更少的面向機器的抽象機制,面向對象使我們在實際軟件開發中能處理更多的問題。
版權聲明:本文內容由互聯網用戶自發貢獻,該文觀點僅代表作者本人。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如發現本站有涉嫌抄襲侵權/違法違規的內容, 請發送郵件至 舉報,一經查實,本站將立刻刪除。