來談談JAVA面向對象 - 魯班即將五殺,大喬送他回家??


開發IDE為Eclipse或者MyEclipse。

首先,如果我們使用面向過程的思維來解決這個問題,就是第一步做什么,第二步做什么?

魯班即將五殺,大喬送他回家

這個現象可以簡單地拆分為兩步,代碼大概是這個樣子的:

public class Test01 {
	
	public static void main(String[] args) {
		System.out.println("魯班即將五殺");
		System.out.println("大喬送他回家");
	}

}

面向過程的思維大概就是這樣。

如果我們用面向對象的思維來看待這個問題,首先,得抽象出有哪幾個對象。

魯班類:

/**
 * 魯班類
 * @author Administrator
 *
 */
public class Luban {
	
	private String name = "魯班"; //英雄的名字
	private int killCount = 0; 	  //擊殺個數
	
	
	
}

因為魯班會有一個從 first bloodpenta kill 的過程 , 在這個過程中,需要對killCount 這個變量一步步遞增,所以,我們給它再加一個kill方法。

public void kill(){
	killCount++;
	
	switch (killCount) {
	case 1:
		System.out.println("First Blood!");
		break;
	case 2:
		System.out.println("Double Kill!");
		break;
	case 3:
		System.out.println("Triple kill!");
		break;
	case 4:
		System.out.println("Quadra kill!");
		break;
	case 5:
		System.out.println("Penta kill!");
		break;

	default:
		break;
	}
	
}

這個時候,我們發現,訪問不了私有變量。我們需要給name和killCount添加對應的get,set方法:

Alt + S --> Generator Getters and Setters -->

這樣就自動生成了!

至此,魯班類告一段落,接下來編寫大喬類:

/**
 * 大喬類
 * @author Administrator
 *
 */
public class Daqiao {
	
	private String name = "大喬";
	
	/**
	 * 放大招的方法
	 */
	public void DaZhao(Luban luban){
		
	}
	
}

大招方法需要把魯班給裝進去,大家思考如何實現送魯班回家的過程?

這邊我提供一個思路,給魯班添加一個私有的布爾屬性 isAtHome,默認是false。當魯班被傳遞進大喬的大招方法里之后,就改為true。

private boolean isAtHome = false; //是否回泉水?

別忘了生成 get set 方法。

於是乎,大招方法就變成了這樣:

/**
 * 放大招的方法
 */
public void DaZhao(Luban luban){
	luban.setAtHome(true);
}

現在大家再想一個問題,當魯班回泉水了,還能不能繼續調用 kill 方法?

肯定是不能了,修改后的 kill 方法,在killCount++之前就應該return掉:

public void kill(){
	
	if(this.isAtHome){
        setName("魯班七號");
        System.out.println(name + ":我是誰,在干什么??");
		return;
	}

	killCount++;
	
	switch (killCount) {
	case 1:
		System.out.println("First Blood!");
		break;
	case 2:
		System.out.println("Double Kill!");
		break;
	case 3:
		System.out.println("Triple kill!");
		break;
	case 4:
		System.out.println("Quadra kill!");
		break;
	case 5:
		System.out.println("Penta kill!");
		break;

	default:
		break;
	}
	
}

測試:

import bean.Daqiao;
import bean.Luban;

public class Test02 {

	public static void main(String[] args) {
		Luban luban = new Luban();
		luban.kill();
		luban.kill();
		luban.kill();
		luban.kill();
		
		Daqiao dq = new Daqiao();
		
		dq.DaZhao(luban);
		
		luban.kill();
		
		
	}
}

以上就是我們面向對象的一般思路,先抽象出有幾個類,然后設計每個類中有哪些方法?

面向對象有三大特性,分別為繼承,封裝和多態。

繼承

還是這個例子,思考:魯班和大喬都屬於王者峽谷里面的英雄。他們有很多共同的特性。我們可以抽象出一個通用的英雄類,Hero類 。

package bean;

/**
 * 英雄類
 * @author Administrator
 *
 */
public class Hero {
	
	protected String name;
	protected int killCount = 0;
	protected boolean isAtHome = false;
	
	public void kill(){
		
	}
	
	public void DaZhao(){
		
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getKillCount() {
		return killCount;
	}

	public void setKillCount(int killCount) {
		this.killCount = killCount;
	}

	public boolean isAtHome() {
		return isAtHome;
	}

	public void setAtHome(boolean isAtHome) {
		this.isAtHome = isAtHome;
	}
	
	
}

然后讓魯班和大喬都繼承這個類。

對魯班而言,繼承了Hero類以后,只需要重寫kill即可,省去了很多代碼:

package bean;

/**
 * 魯班類
 * @author Administrator
 *
 */
public class Luban extends Hero{
	
	public void kill(){
		
		if(this.isAtHome){
			System.out.println(name + ":我是誰,在干什么??");
			return;
		}
	
		killCount++;
		
		switch (killCount) {
		case 1:
			System.out.println("First Blood!");
			break;
		case 2:
			System.out.println("Double Kill!");
			break;
		case 3:
			System.out.println("Triple kill!");
			break;
		case 4:
			System.out.println("Quadra kill!");
			break;
		case 5:
			System.out.println("Penta kill!");
			break;
	
		default:
			break;
		}
		
	}

	
}

大喬類也是同樣的道理:

package bean;

/**
 * 大喬類
 * @author Administrator
 *
 */
public class Daqiao extends Hero{

	/**
	 * 放大招的方法
	 */
	public void DaZhao(Luban luban){
		luban.setAtHome(true);
	}
	
}

這個時候,我們可以看到,繼承的一個好處就是可以省去很多重復的代碼,提高了代碼的復用率。

封裝

現在我們考慮如何讓java程序來播放一個音樂?

經過改造后的魯班 kill 方法:

public void kill(){
	
	if(this.isAtHome){
		setName("魯班七號");
		System.out.println(name + ":我是誰,在干什么??");
		return;
	}

	killCount++;
	
	switch (killCount) {
	case 1:
		
		//解析音樂地址
		try{
			URL codebase = new URL("file:/E:/workspace/demos/1.wav");
			AudioClip a = Applet.newAudioClip(codebase);
			a.play(); //播放音樂
			Thread.sleep(2000);
		}catch(Exception e){
			System.out.println("錯就錯唄,無所謂!");
		}
		
		System.out.println("First Blood!");
		break;
		
	case 2:
		
		//解析音樂地址
		try{
			URL codebase = new URL("file:/E:/workspace/demos/2.wav");
			AudioClip a = Applet.newAudioClip(codebase);
			a.play(); //播放音樂
			Thread.sleep(2000);
		}catch(Exception e){
			System.out.println("錯就錯唄,無所謂!");
		}
		System.out.println("Double Kill!");
		break;
	case 3:
		
		//解析音樂地址
		try{
			URL codebase = new URL("file:/E:/workspace/demos/3.wav");
			AudioClip a = Applet.newAudioClip(codebase);
			a.play(); //播放音樂
			Thread.sleep(2000);
		}catch(Exception e){
			System.out.println("錯就錯唄,無所謂!");
		}
		
		System.out.println("Triple kill!");
		break;
	case 4:
		//解析音樂地址
		try{
			URL codebase = new URL("file:/E:/workspace/demos/4.wav");
			AudioClip a = Applet.newAudioClip(codebase);
			a.play(); //播放音樂
			Thread.sleep(2000);
		}catch(Exception e){
			System.out.println("錯就錯唄,無所謂!");
		}
		System.out.println("Quadra kill!");
		break;
	case 5:
		//解析音樂地址
		try{
			URL codebase = new URL("file:/E:/workspace/demos/5.wav");
			AudioClip a = Applet.newAudioClip(codebase);
			a.play(); //播放音樂
			Thread.sleep(2000);
		}catch(Exception e){
			System.out.println("錯就錯唄,無所謂!");
		}
		System.out.println("Penta kill!");
		break;

	default:
		break;
	}
	
}

從代碼中,我們可以發現,播放音樂的代碼很多都是重復的,這個時候,我們就考慮能不能單獨封裝一個類,來播放音樂。

比如,我們可以新建一個音樂工具類,下次要播放音樂的時候,就調用這個類的方法。

package util;

import java.applet.Applet;
import java.applet.AudioClip;
import java.net.URL;

public class MusicUtil {
	
	/**
	 *  音樂工具類
	 * @param path 音樂地址
	 * @param seconds 秒數
	 */
	public static void playWav(String path,int seconds){
		try{
			URL codebase = new URL("file:/" + path);
			AudioClip a = Applet.newAudioClip(codebase);
			a.play(); //播放音樂
			Thread.sleep(seconds * 1000);
		}catch(Exception e){
			System.out.println("錯就錯唄,無所謂!");
		}
	}
	

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		MusicUtil.playWav("E:\\workspace\\demos\\luban.wav", 5);
		
	}

}

有了這個工具類,之前播放音樂的代碼只需要一句話便可代替:

package bean;

import util.MusicUtil;

/**
 * 魯班類
 * @author Administrator
 *
 */
public class Luban extends Hero{
	
	public void kill(){
		
		if(this.isAtHome){
			setName("魯班七號");
			System.out.println(name + ":我是誰,在干什么??");
			return;
		}
	
		killCount++;
		
		switch (killCount) {
		case 1:
			
			MusicUtil.playWav("E:/workspace/demos/1.wav", 2);
			
			System.out.println("First Blood!");
			break;
			
		case 2:
			
			MusicUtil.playWav("E:/workspace/demos/2.wav", 2);
			System.out.println("Double Kill!");
			break;
		case 3:
			
			MusicUtil.playWav("E:/workspace/demos/3.wav", 2);
			
			System.out.println("Triple kill!");
			break;
		case 4:
			MusicUtil.playWav("E:/workspace/demos/4.wav", 2);
			System.out.println("Quadra kill!");
			break;
		case 5:
			MusicUtil.playWav("E:/workspace/demos/5.wav", 2);
			System.out.println("Penta kill!");
			break;
	
		default:
			break;
		}
		
	}
	
	public void say(){
		
		MusicUtil.playWav("E:/workspace/demos/luban.wav", 5);
	}

	
}

甚至,這些工具類,我們還可以單獨打成一個jar包,發布到網上,供別人使用!

新建一個musicutil項目:

我們添加一個util包,把剛才的MusicUtil.java復制進來即可:

現在開始打包,右鍵項目,選擇Export,Export:


如果下次我們想要在其他項目中播放音樂的話,只需要引入這個jar即可,甚至,你要是閑得無聊的話,可以發布到網上,供別人下載使用。

回到封裝的解說,我們可以把那些經常使用的,重復率特別高的代碼,封裝成一個方法,達到代碼復用的目的。如果不封裝,可想而知,我們的類中底層代碼會特別多,不利於旁人理解,也不利於我們今后維護代碼,因為方法名是我們自己取的,所以日后也可以很好的理解當初的代碼是什么意思。

封裝的另一個好處就是,有些東西,我不會,但是別人封裝好了,我是不是可以去下載拿來用??

又比如jdk給我們封裝大部分java開發需要的類,這些類,很多都極其復雜,但是因為sun公司已經給我們封裝好了,所以我們也完全不需要去關心其底層的實現,比如String,比如HashMap,直接拿來就用,而且效率很高!

所以,我認為,封裝另一個好處就是,我不會的東西,只要有人會,就好了,我照樣可以拿來開發程序!

多態

/**
 * 大喬類
 * @author Administrator
 *
 */
public class Daqiao extends Hero{

	/**
	 * 放大招的方法
	 */
	public void DaZhao(Luban luban){
		luban.setAtHome(true);
		luban.say();
	}
	
}

回顧大喬類,問一下大家,大喬的大招對魯班有效,對蘭陵王有沒有效?對露娜有沒有效?

如果我們現在新建了一個露娜類:

package bean;

import util.MusicUtil;

/**
 * 露娜類
 * @author Administrator
 *
 */
public class Luban extends Hero{
	
	public void kill(){
		
		if(this.isAtHome){
			setName("露娜");
			System.out.println(name + ":我是誰,在干什么??");
			return;
		}
	
		killCount++;
		
		switch (killCount) {
		case 1:
			
			MusicUtil.playWav("E:/workspace/demos/1.wav", 2);
			
			System.out.println("First Blood!");
			break;
			
		case 2:
			
			MusicUtil.playWav("E:/workspace/demos/2.wav", 2);
			System.out.println("Double Kill!");
			break;
		case 3:
			
			MusicUtil.playWav("E:/workspace/demos/3.wav", 2);
			
			System.out.println("Triple kill!");
			break;
		case 4:
			MusicUtil.playWav("E:/workspace/demos/4.wav", 2);
			System.out.println("Quadra kill!");
			break;
		case 5:
			MusicUtil.playWav("E:/workspace/demos/5.wav", 2);
			System.out.println("Penta kill!");
			break;
	
		default:
			break;
		}
		
	}
	
	
	public void say(){
		
		MusicUtil.playWav("E:/workspace/demos/zixia.wav", 5);
	}

	
}

同時,在父類中,添加say方法:

public void say(){
		
		
}

這個時候,大喬的大招是無法裝進露娜類的。

測試:

對大喬來說,不管你是什么英雄,只要你繼承了Hero類,都可以分分鍾送你回家!所以,我們要改變大招方法的參數:

/**
 * 放大招的方法
 */
public void DaZhao(Hero hero){
	hero.setAtHome(true);
	hero.say();
}

這就是所謂的多態。

從這個例子當中,我們可以看出,多態最直接的好處就是某個方法中,同一個參數可以接收多種類型的數據。

比如剛才大喬的例子,如果我們不用多態,那么大招方法就得重載很多個,比如針對魯班,就得有一個大招方法。針對蘭陵王,又需要一個大招方法。這樣會導致方法特別多,而且不易維護。如果,我們直接設定所有的英雄都必須繼承自英雄類,那么,大招方法,只需要一個英雄類的參數即可,一個方法足以。

所以,多態的好處,我認為,就是方便傳參。而且,更多的,在設計類的時候,就應該預想到會有什么類型的參數傳進來,這是需要提前考慮的。

作業:
用面向對象的思維來描述以下的現象:

蘭陵王被王昭君的大招凍住了,結果對方的項羽把蘭陵王推了出去!

提示:
蘭陵王,王昭君,項羽 都應該繼承自Hero類。


個人博客:http://java520.top/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM