天天看點

由淺入深,帶你玩轉幾種常用java設計模式

PART A:前言

平常我們都在敲代碼,為了要實作一些我們希望看到的功能,敲一大堆一大堆。往往就會忽略了這樣的一個問題。

你會問敲代碼就讓我們老老實實的敲代碼吧,為什麼要那麼麻煩的去考慮那麼多?當然了現在這樣一說你肯定會回答我們肯定不可能就一心隻會死頭死腦的無腦敲代碼啊。是吧?那麼我們還要考慮一些什麼事情呢?這麼跟大家說吧,我們現在敲代碼做項目就像做房子,現在我們做的事情是,一塊一塊的不斷的壘磚塊,無腦壘。而不管他壘的好不好看美不美觀,也不管他消耗的磚塊是否太多。是不是?再打個比方,從國小起我們就開始拿着筆寫作文。剛剛開始那個時候,還記得自己是怎麼寫作文的麼?是不是照着課本寫?又或者就是寫一些流水賬似的東西?記得那個時候能夠記兩筆流水賬已經能夠讓自己激動不已了是吧?呵呵。那你還記得是從什麼時候開始,老師開始給你講文章的結構文章的排篇布局,開始給你介紹各種諸如開門見山等等的文章寫法的?今天就讓我們回到那個時候。

接下來我們開始接觸一些比較常用的java設計模式。

PART B:

         B-1工廠模式

你可以從網上找到許許多多關于這個(java設計模式)的文檔與資料,如果你下載下傳過看過不止四五份你就會發現,雖然他們的說法都有自己的一套,但是總是有千人一面的地方。而我要告訴你的是,這一面,就是你所需要的東西了。

對于工廠模式而言,每個人都會有自己的體會與看法。就比如有的人說他是将代碼按照其功能子產品化了,也有人說他就是一個配置設定機制,好比把不同的工作交給不同的人去做一樣,将對象的功能的實作交給一些特制的類去完成,等等等等。隻要是接觸過的人,就可以說出一種他的立場上看到的工廠模式。

但是在這裡我要告訴你的是,工廠模式他的關鍵是:将建立對象和使用對象分開。在這樣的一個過程中不僅僅達到了理清編寫者自己思路的作用,也使得代碼脈絡更加清晰明朗,簡潔易懂。不知道大家還記不記得曾經講哈夫曼樹的時候那棵充斥我們一個多禮拜的哈夫曼樹?我想說,現在這棵樹是沒了,但是重新出現了一座龐大的工廠……在這個工廠裡邊分工明确權責分明,他的每一個子工廠都隻負責生産某一種特别的産品,而每一種産品也對應着每一個子工廠的生産線。現在隻要想編寫一個程式,就不知道絕的先考慮将它“工廠化”,将它的每一個步驟每一個功能先大卸八塊的區厘清楚,然後才開始代碼的實際編寫工作……

好了,閑話就不多說了,下面我們就通過執行個體來講講什麼是建立對象和使用對象分開。

(例)

比如我想造一輛寶馬車并讓它跑起來,以前我們都是寫一個寶馬車的類然後直接在這個類裡邊執行個體化一個他的對象,完了以後緊接着在下邊寫寶馬車的跑的方法,是吧?但是工廠模式不這麼做,工廠模式怎麼做呢?請看下面的步驟:

1.寫一個車的接口,并在裡邊定義一個車的go()方法:

public interface Car {
	public void go();
}
           

 2.寫一個寶馬車的類,讓他去繼承上面這個車的總接口,并且實作裡邊的方法:

public class BMW implements Car{
	public void go() {
	}
}
           

 3.是不是少了什麼?呵呵你有車的接口和實作類了當然得有造車工廠咯,是吧?于是我們同樣給它定義一個造車工廠總接口以及一個繼承并且實作它的寶馬造車工廠:

public interface CarFactory {
	public Car build(String name) ;
}
           
public class BMWFactory implements CarFactory{
	
 private static  BMWFactory ins;
	 
	 public static BMWFactory getIns(){
		 if(null==ins){
			 ins=new BMWFactory();
		 }
		 return ins;
	 }
	 
	 BMWFactory(){}
	 
	
	public Car build(String name) {
		
		 if(name.equals("BMW")){
			
			 return new BMW();
		 }
		
		return null;
	}

}
           

 4.有的人就會有點牢騷了,我不想老是自己跑工廠去,那樣多麻煩!是吧?好,那麼我們就給他寫一個且車代理商:

public class AgentFactor {
	private static AgentFactor ins;
	public static AgentFactor getIns(){
		if(ins==null){
			ins=new AgentFactor();
		}
		return ins;
	}
	
	//取得制定品牌 的汽車
	public CarFactory getCarFactor(String Name){
		if(Name.equals("BMW")){
			return new BMWFactory();
		}
		return null;
	}
}
           

5.好了,車有了,造車工廠有了,連代理商都給你搞定了,那麼就讓我們來寫個主函數讓我們的寶馬車跑起來吧!

public class CarTest {
	public void driver(){
		
		CarFactory ic=AgentFactor.getIns().getCarFactor("BMW");
		Car mini=ic.build("MINI");
		mini.go();
	}
}
           

 當然了,也不是真的就讓上面的代碼跑起來,細心如你,肯定會發現上面的這幾行代碼是跑不起來的,是不是?具體是為什麼呢,哈哈就留給你咯!

雖然上面給大家的幾行代碼不能夠直接跑起來,但是通過他們,我想大家對于工廠模式這個概念應該會有一個比較清晰的把握了吧。再次說一遍:工廠模式,就是将對象的建立與使用分開。這樣做的目的,自己開動腦經咯~

B-2 事件監聽模式

相信大家接觸java以來就一直在跟滑鼠監聽器等等各種事件監聽器打交道,對于這些個零零總總的各式各樣的監聽器也并不陌生吧?但是對于這些滑鼠監聽器啊鍵盤監聽器啊什麼的,他的具體的實作方式是怎麼樣的你是否清楚呢?如果你是一個足夠細心而好學的人,那麼我接下來要說的東西對你來說可能是沒什麼必要的了,因為你肯定看過這些監聽器它的源碼,也必然知道他的運作機制與原理了。

下面讓我們用代碼執行個體來看一看這事件監聽的原型吧!

(例)在做通信的時候我們曾經做過收到消息并且讓他顯示在一個JTEXTAREA上面,但是若我想要讓他顯示在JLABEL上的話就得對代碼進行一些關聯的改動,很是麻煩。我們且看事件監聽模式怎麼解決這個問題:

1.寫一個消息的接口,在裡邊定義幾項消息的基本屬性:

//定義一個消息接口,所有的消息都是他的實作類
public interface Msg {
	public byte getType();//傳回消息類型
	public String getText();//傳回消息内容
}
           

 2.寫一個具體的消息類,繼承消息接口:

public class TextMsg implements Msg{
	private String text;
	//具體的消息類,繼承消息接口
	public TextMsg(String text){
		this.text=text;
	}
	public String getText() {
		
		return this.text;
	}
public byte getType() {
		return 2;
	}

}
           

 3.第三布我們要做的是,編寫一個監聽器接口:

//處理器接口定義
public interface MsgProcess {
	//具體的處理器,所有的處理器實作類都必須實作這個方法
	 void processMsg(Msg msg);
}
           

 4.編寫你需要的監聽器,比如你想讓消息呈現在JLABEL上:

import javax.swing.JLabel;

public class JLabelProcess extends JLabel implements MsgProcess{
	public void processMsg(Msg msg) {
		String t=msg.getText();

		this.setText(t);
		
		System.out.println(t);
	}
}
           

如果你還想讓消息顯示在其他地方,比如,JBUTTON上,你可以另外寫一個監聽器的類繼承上面的監聽器接口: 

import javax.swing.JButton;

public class JButtonProcess extends JButton implements MsgProcess{
	public void processMsg(Msg msg) {
		String t=msg.getText();
		this.setText(t);
	}
}
           

 5.編寫一個線程,我們将模拟生成消息(事件源)放在這個線程裡邊來做:

public class NetConn extends Thread{
	
	//儲存事件監聽器的隊列
	ArrayList<MsgProcess>  ips=new ArrayList<MsgProcess>();
	
	public void addMsgProcess(MsgProcess p){
		ips.add(p);
	}
	
	public void run(){
		//模拟事件源
		int i=0;
		while(true){
			
			Msg s=new TextMsg("我收到的消息是:"+i);
			i++;
			for(int t=0;t<ips.size();t++){
				MsgProcess pro=ips.get(t);
				pro.processMsg(s);
			}
			try {
				this.sleep(1000);
			} catch (InterruptedException e) {e.printStackTrace();}
		}
	}
	
	
}
           

 6.好的,做完了上面的這些工作,接下來就讓我們來寫一個主函數吧:

import java.awt.FlowLayout;
import javax.swing.JFrame;

public class Main {
	public static void main(String srga[]){
		NetConn nc=new NetConn();
		nc.start();
		
		JLabelProcess lp=new JLabelProcess();
		nc.addMsgProcess(lp);
		JButtonProcess tp=new JButtonProcess();
		nc.addMsgProcess(tp);
		
		JFrame jf=new JFrame("test");
		
		jf.add(tp);
		
		jf.setSize(300,300);
		jf.setLayout(new FlowLayout());
		jf.add(lp);
		jf.setVisible(true);
		jf.setDefaultCloseOperation(3);
	}
}
           

 事件監聽模式介紹到這裡你是不是心裡隐隐感覺,這個世界上的好多事情都變成了一個個事件源和一個個監聽處理器了?如果對于事件監聽模式還有一些不解或者困惑,請細心看上面提供的代碼示例,慢慢體會它裡邊所蘊含的一些東西,相信你會獲得意想不到的收獲的!

B-3單例模式

好了,說完了兩種比較羅嗦一點的工廠和事件監聽模式,下面讓我們來看看一種比較簡單的java設計模式:單例模式。對于單例模式我想我不用說大家也能夠說出這種模式就是實作單執行個體的,沒錯,就是如此!

單例就是:保證一個類僅有一個執行個體,僅提供一個通路它的全局通路點。

他的适用性在于:

 1.當類隻能有一個執行個體而且客戶可以從一個衆所周知的通路點通路它時。

 2.當這個唯一執行個體應該是通過子類化可擴充的,并且客戶應該無需更改代碼就能使用一個擴充的執行個體時。

話不多說,請君看我代碼示例:

public class Singleton {
    
    private static Singleton sing;

    private Singleton() {
        
    }
    
    public static Singleton getInstance() {
        if (sing == null) {
            sing = new Singleton();
        }
        return sing;
    }
}
           

 public class Test {

public static void main(String[] args) {
        Singleton sing = Singleton.getInstance();
        Singleton sing2 = Singleton.getInstance();
        
        System.out.println(sing);
        System.out.println(sing2);
    }
}
           

ok,今天就介紹到這兒,這三種基本的java設計模式平時用的很多,當然,設計模式還有很多,由于時間關系我們在這裡不便羅嗦太多,你可以自己去了解去學習去運用。但是要記住一點,不管是什麼模式,他的實用性都展現在大型項目或者一些代碼量很大的項目上。當你敲的代碼足夠多了,你就自然會對這些設計模式的作用和意義有一個深刻全面的體會。不管是工廠模式還是事件監聽模式,又或者甚至是單例模式,他們的光芒都要在無數行代碼之上才能夠足夠彰顯足夠耀眼。

繼續閱讀