1. 程式人生 > >Java中常見的設計模式---簡單工廠模式、工廠方法模式和單例模式

Java中常見的設計模式---簡單工廠模式、工廠方法模式和單例模式

在講設計模式之前,我們首先來說一下面向物件思想的設計原則,在實際的開發中,我們要想更深入的瞭解面向物件思想,就必須熟悉前人總結過的面向物件的思想的設計原則:

1.單一職責原則:“高內聚,低耦合”,也就是說,每個類應該只有一個職責,對外只能提供一種功能,而引起類變化的原因應該只有一個。在設計模式中,所有的設計模式都遵循這一原則。

2.開閉原則:核心思想:一個物件對擴充套件開放,對修改關閉,也就是說對類的改動是通過增加程式碼進行的,而不是修改現有程式碼。

3.里氏替換原則:在任何父類出現的地方都可以用它的子類來替代。其實就是說:同一個繼承體系中的物件應該有共同的行為特徵。

4.依賴注入原則:要依賴於抽象,不要依賴於具體實現。其實就是說:在應用程式中,所有的類如果使用或依賴於其他的類,則應該依賴這些其他類的抽象類,而不是這些其他類的具體類。為了實現這一原則,就要求我們在程式設計的時候針對抽象類或者介面程式設計,而不是針對具體實現程式設計。

5.介面分離原則:不應該強迫程式依賴它們不需要使用的方法。其實就是說:一個介面不需要提供太多的行為,一個介面應該只提供一種對外的功能,不應該把所有的操作都封裝到一個介面中。

6.迪米特原則:一個物件應當對其他物件儘可能少的瞭解,其實就是說:降低各個物件之間的耦合,提高系統的可維護性。在模組之間應該只通過介面程式設計,而不理會模組的內部工作原理,它可以使各個模組耦合度降到最低,促進軟體的複用。

簡單工廠模式

簡單工廠模式也叫靜態工廠方法模式 
設計一個工廠類:

工廠類提供一些靜態方法,間接的去建立具體的物件

下來我們通過一個具體的例子來學習一下。

//提供了一個動物抽象類
public abstract  class Animal {
	
	//抽象功能
	public abstract void eat() ;
}
public class Cat extends Animal {

	@Override
	public void eat() {
		System.out.println("貓吃魚...");
	}

}
public class Dog extends Animal{

	@Override
	public void eat() {
		System.out.println("狗吃骨頭...");
	}
	
}
//動物工廠類
public class AnimalFactory {

	//無參構造私有:外界不能建立該類物件
	private AnimalFactory() {
		
	}
	
	//提供一些靜態功能,間接的建立具體物件
	/*public static Cat createCat() {
		return new Cat() ;
	}
	
	//狗類
	public static Dog createDog() {
		return new Dog() ;
	}*/
	
	//想辦法用多型的形式解決:程式碼擴充套件性
	public static Animal createAnimal(String type) {
		if("cat".equals(type)) {
			return new Cat() ;
		}else if("dog".equals(type)) {
			return new Dog() ;
		}
		return null;
	}
	
}
public class AnimalDemo {

	public static void main(String[] args) {
		
		//養貓
		Cat c = new Cat() ;
		c.eat();
		//養狗
		Dog d = new Dog() ;
		d.eat(); 
		
		System.out.println("---------------------");
		
		//優化改進之後,呼叫工廠類裡面的方法
		/*Cat cc = AnimalFactory.createCat() ;
		cc.eat();
		Dog dd = AnimalFactory.createDog() ;
		dd.eat();*/
		
		//改進:使用抽象類多型的形式改進工廠類
		Animal a = AnimalFactory.createAnimal("cat") ;
		a.eat();
		a = AnimalFactory.createAnimal("dog") ;
		a.eat();
		
		a = AnimalFactory.createAnimal("pig") ;
		//java.lang.NullPointerException
		//物件進行非空判斷
		if(a!=null) {
			a.eat();
		}else {
			System.out.println("抱歉,當前工廠類不提供該動物類的建立");
		}
	}
}

從程式碼中也可以發現,簡單工廠模式的優缺點。

優點:

        客戶端不需要在負責物件的建立,從而明確了各個類的職責

缺點:

        這個靜態工廠類負責所有物件的建立,如果有新的物件增加,或者某些物件的建立方式不同,就需要不斷的修改工廠類,不利於後期的維護(如程式碼中pig物件的增加,則必須增加pig類並修改AnimalFactory工廠類)

工廠方法模式

工廠方法模式
提供一個抽象類(抽象工廠)還需要提供一個介面(工廠介面),每一個具體的類都有對應的工廠類(實現工廠介面)

具體物件的建立工作由繼承抽象工廠的具體類實現

//抽象類
public abstract class Animal {

	public abstract void eat() ;
}
public class Cat extends Animal {

	@Override
	public void eat() {
		System.out.println("貓吃魚...");
		
	}
	
}
public class Dog extends Animal {

	@Override
	public void eat() {
		System.out.println("狗吃骨頭...");
	}

}
public interface Factory {
	
	//該工廠介面的方法的返回值是抽象工廠類
	public abstract Animal creatAnimal() ;
}
//貓的工廠類--->建立一隻貓
public class CatFactory implements Factory {

	@Override
	public Animal creatAnimal() {
		return  new Cat() ;
	}

}
public class DogFactory implements Factory {

	@Override
	public Animal creatAnimal() {
		return new Dog();
	}

}
public class AnimalDemo {
	
	public static void main(String[] args) {
		
		//建立Factory物件
		//介面多型的形式
		Factory f = new CatFactory() ;
		Animal a = f.creatAnimal() ;
		a.eat();
		System.out.println("-------------------");
		f = new DogFactory() ;
		a = f.creatAnimal() ;
		a.eat();
		
	}
}
優點:
客戶端不需要在負責物件的建立(不需顯示建立具體物件),從而明確了各個類的職責,

如果有新的物件增加,只需要增加一個具體的類和具體的工廠類即可,不影響已有的程式碼,後期維護容易,增強了系統的擴充套件性。

弊端:
書寫程式碼量大了!

單例模式

單例模式核心思想:某些類的物件在建立的時候 ,在系統記憶體始終只有一個物件!
單例模式分類:

1)餓漢式 2)懶漢式(類似於多執行緒環境..)

兩種分類在設計上幾乎一樣:
1)定義個類,將該類的無參構造方法私有化
2)在該類的成員位置建立該類物件 並且一定要私有化,防止外界更改這個物件
3)在該類中提供靜態成員方法(返回值就是建立的那個物件),能被當前類直接呼叫,static修飾


餓漢式:

在載入那個類的時候,物件的建立工作就已經完成了!

//學生類
public class Student {

	//無參構造私有化,目的為了防止使用者建立物件的時候,會產生多個物件!
	//為了不讓直接通過構造方法建立該類物件
	private Student() {}
	
	//成員位置建立該類的例項
	//靜態方法只能訪問靜態變數
	//加入私有修飾
	private static Student s = new Student() ; //靜態的類變數
	
	//提供一個公共的成員方法
	public static Student getStudent() {
		return s ;
	}
}
public class StudentDemo {
	
	public static void main(String[] args) {
		
		//建立學生物件
		//在記憶體中有多個物件了
		/*Student s1  = new Student() ;
		Student s2  = new Student() ;
		System.out.println(s1==s2);*/	//false
		
		//修改當前那個類的成員
		//Student.s=null ;
		//直接更改了物件的值,所以學生類中應用private修飾
		
		Student s1 = Student.getStudent() ;
		Student s2 = Student.getStudent();
		System.out.println(s1==s2);//true

		System.out.println(s1);//[email protected]
		System.out.println(s2);//[email protected]
	}
}
懶漢式:
符合單例模式核心思想
1)自定義一個類,將無參構造私有化
2)在成員位置宣告變數
3)提供公共靜態功能,在裡面判斷的建立該類物件,返回該類物件

如果是開發中,那麼就使用餓漢式(餓漢式它不會出現問題的單例模式)
如果是面試中,那麼使用懶漢式(因為他是可能出現問題的一種單例模式)

面試題:
你使用過單例模式嗎?簡單介紹一種單例模式,請用程式碼設計
面試官想問的是:使用設計單例的懶漢式,能否想到使用同步機制解決執行緒的安全問題..

懶漢式(延遲載入 -->懶載入)
可能會出現問題
--->多執行緒的問題
--->校驗多執行緒安全問題的標準
1)是否是多執行緒環境
2)是否有共享資料

3)是否有多條語句對共享資料進行操作  (使用同步機制進行操作)

public class Teacher {
	
	//無參構造私有化
	private Teacher() {
		
	}
	
	//在成員位置宣告變數
	//私有化,並且用static修飾來實現資料共享
	private static Teacher t = null ;
	
	//提供公共的靜態功能
	/*public static Teacher getTeacher() {
		//如何建立該類物件,需要用的時候在建立
		//t1,t2,t3
		//在這裡需要判斷
		synchronized (t) {
			if(t==null) {
				t = new Teacher() ;
			}
			return t ;
		}
		
	}*/
	
	//靜態的同步方法  (鎖物件: 類名.class)
	public synchronized static Teacher getTeacher() {
		if(t==null) {
			t = new Teacher() ;
		}
		return t ;
	}
}
public class TeacherDemo {
	
	public static void main(String[] args) {
		
		//呼叫getTeacher()功能
		Teacher t1 = Teacher.getTeacher() ;
		Teacher t2 = Teacher.getTeacher() ;
		System.out.println(t1==t2);
		System.out.println(t1);//[email protected]
		System.out.println(t1);
		}
}

Runtime類
每個 Java 應用程式都有一個 Runtime 類例項,使應用程式能夠與其執行的環境相連線。
public static Runtime getRuntime()返回與當前 Java 應用程式相關的執行時物件

public Process exec(String command) throws IOException在單獨的程序中執行指定的字串命令。

public class RunTimeDemo {

	public static void main(String[] args) throws IOException {
		
		//建立Runtime類的例項
		Runtime r = Runtime.getRuntime() ;
		
		//開啟某一個程序
		//r.exec("calc") ;//開啟計算器程序
		//r.exec("notepad") ;//開啟notepad程序
		r.exec("mspaint") ;//開啟畫圖程序
	}
}