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") ;//開啟畫圖程序
}
}