Java中面向對象思想設計原則、設計模式、簡單工廠模式、工廠方法模式、單例設計模式之餓漢式和懶漢式、Runtime類

面向對象思想設計原則

在實際的開發中,我們要想更深入的了解面向對象思想,就必須熟悉前人總結過的面向對象的思想的設計原則,那么都有哪些原則呢,我們就來了解一下

  • 單一職責原則
    • 其實就是開發人員經常說的”高內聚,低耦合”
  • 開閉原則
    • 核心思想是:一個對象對擴展開放,對修改關閉。其實開閉原則的意思就是:對類的改動是通過增加代碼進行的,而不是修改現有代碼。
  • 里氏替換原則
    • 核心思想:在任何父類出現的地方都可以用它的子類來替代。其實就是說:同一個繼承體系中的對象應該有共同的行為特征。
  • 依賴注入原則
    • 核心思想:要依賴于抽象,不要依賴于具體實現。
  • 接口分離原則
    • 核心思想:不應該強迫程序依賴它們不需要使用的方法。
  • 迪米特原則
    • 核心思想:一個對象應當對其他對象盡可能少的了解

設計模式

設計模式在我們開發中還是經常用到的,那么,下面我們來學習一下

  • 設計模式概述

    • 設計模式(Design pattern)是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。
  • 設計模式不是一種方法和技術,而是一種思想
    設計模式和具體的語言無關,學習設計模式就是要建立面向對象的思想,盡可能的面向接口編程,低耦合,高內聚,使設計的程序可復用

  • 學習設計模式能夠促進對面向對象思想的理解,反之亦然。它們相輔相成

  • 設計模式的幾個要素:

  • 名字 必須有一個簡單,有意義的名字

  • 問題 描述在何時使用模式

  • 解決方案 描述設計的組成部分以及如何解決問題

  • 效果 描述模式的效果以及優缺點

  • 設計模式的分類

  • 創建型模式 對象的創建

  • 結構型模式 對象的組成(結構)

  • 行為型模式 對象的行為

創建型模式:簡單工廠模式,工廠方法模式,抽象工廠模式,建造者模式,原型模式,單例模式。(6個)結構型模式:外觀模式、適配器模式、代理模式、裝飾模式、橋接模式、組合模式、享元模式。(7個)行為型模式:模版方法模式、觀察者模式、狀態模式、職責鏈模式、命令模式、訪問者模式、策略模式、備忘錄模式、迭代器模式、解釋器模式。(10個)

設計模式的分類雖然很多,但是我們平時能用到的也就下面幾種而已,所以不要被它這么多模式所嚇倒。

  • 常見的設計模式 簡單工廠模式和工廠方法模式(接口)
    • 模版設計模式(抽象類)
    • 裝飾設計模式(IO流)
    • 單例設計模式(多線程)
    • 適配器模式(GUI)

下面我們就來學習我們常用的幾種設計模式,讓大家掌握,熟悉,并運用到自己的項目中,學會學以致用。

簡單工廠模式

  • 簡單工廠模式概述
    • 又叫靜態工廠方法模式,它定義一個具體的工廠類負責創建一些類的實例

我們來寫一個簡單的例子來解釋簡單工廠模式

/* * 抽象的動物類,里面有抽象的方法 */
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 Animal createAnimal(String type) {
 if ("dog".equals(type)) { 
return new Dog();
 } else if ("cat".equals(type)) { 
return new Cat();
 } else { 
return null;
 } 
}
}
/* * 測試類 */
public class AnimalDemo { 
public static void main(String[] args) { 
// 工廠有了后,通過工廠給造
 Animal a = AnimalFactory.createAnimal("dog"); 
a.eat();
 a = AnimalFactory.createAnimal("cat");
 a.eat();
 // NullPointerException 
a = AnimalFactory.createAnimal("pig");
 if (a != null) { 
a.eat();
 } else { 
System.out.println("對不起,暫時不提供這種動物"); 
} 
}
}

以前我們在學代碼的時候,不會去創建這個動物的工廠類,而是直接具體類的調用,比如:

Dog d = new Dog();
 d.eat(); 
Cat c = new Cat(); 
c.eat();  

現在我們運用了簡單工廠模式后,就不用每次用的時候去new對象,而是直接去調用這個工廠類里面的具體方法,它會給我們返回一個已經new好的對象。那么這樣做有什么有缺點呢,我們來總結一下。

  • 優點
    • 客戶端不需要在負責對象的創建,從而明確了各個類的職責
  • 缺點
    • 這個靜態工廠類負責所有對象的創建,如果有新的對象增加,或者某些對象的創建方式不同,就需要不斷的修改工廠類,不利于后期的維護

當我們要用一個模式時,當這個模式的優點大于缺點的時候,我們就可以使用了,但是在簡單工廠模式中我們可以看到它的缺點,當我們有新的對象增加時,就要不斷的修改工廠類,所以不推薦大家用簡單工廠模式,那么我們要用什么呢,這就引出了我們要學的下一個知識點工廠方法模式

工廠方法模式

  • 工廠方法模式概述
    • 工廠方法模式中抽象工廠類負責定義創建對象的接口,具體對象的創建工作由繼承抽象工廠的具體類實現。

我們就來用工廠方法模式對上面的那個例子進行改進

/* * 抽象的動物類,里面有抽象的方法 */
public abstract class Animal { 
public abstract void eat();
}
/* * 工廠類接口,里面有抽象的創造動物的方法 */
public interface Factory { 
public abstract Animal createAnimal();
}
/* * 具體的貓類繼承抽象動物類,重寫抽象方法 */
public class Cat extends Animal { 
@Override 
public void eat() { 
System.out.println("貓吃魚"); 
}
}
/* * 貓工廠類實現工廠類并實現它的抽象方法,返回一個貓對象 */
public class CatFactory implements Factory { 
@Override 
public Animal createAnimal() { 
return new Cat();
 }
}
/* * 具體的狗類繼承抽象動物類,重寫抽象方法 */
public class Dog extends Animal { 
@Override 
public void eat() { 
System.out.println("狗吃肉"); 
}
}
/* * 狗工廠類實現工廠類并實現它的抽象方法,返回一個狗對象 */
public class DogFactory implements Factory { 
@Override 
public Animal createAnimal() { 
return new Dog(); 
}
}
/* * 測試類 */
public class AnimalDemo { 
public static void main(String[] args) { 
// 需求:我要買只狗 
Factory f = new DogFactory(); 
Animal a = f.createAnimal();
 a.eat(); 
//需求:我要買只貓 
f = new CatFactory(); 
a = f.createAnimal(); 
a.eat();
 }
}

運行程序,控制臺會輸出,狗吃肉 貓吃魚
我們仔細觀察用工廠方法模式比比簡單工廠模式多了幾個類,但是當我們在需要一種動物豬時,我們就不用去修改工廠類里面的代碼了,只需用創建一個豬類繼承抽象動物類,重寫抽象方法,再創建一個豬的工廠類實現工廠類并實現它的抽象方法,就可以了。代碼具有很強的維護性和擴展性,那么我們來分析一下工廠方法模式的優缺點。

  • 優點
    • 客戶端不需要在負責對象的創建,從而明確了各個類的職責,如果有新的對象增加,只需要增加一個具體的類和具體的工廠類即可,不影響已有的代碼,后期維護容易,增強了系統的擴展性
  • 缺點
    • 需要額外的編寫代碼,增加了工作量

我們可以看到工廠方法模式的優點明顯大于缺點,所以推薦大家使用。

單例設計模式

  • 單例設計模式概述
    • 單例模式就是要確保類在內存中只有一個對象,該實例必須自動創建,并且對外提供。

如何實現類在內存中只有一個對象呢?
- 構造私有
- 本身提供一個對象
- 通過公共的方法讓外界訪問

那么我們就來學習單例模式中餓漢式懶漢式 這兩種模式,并做以比較

餓漢式

  • 餓漢式:類一加載就創建對象
public class Student { 
// 構造私有 
private Student() { } 
// 自己造一個對象 
// 靜態方法只能訪問靜態成員變量,加靜態 
// 為了不讓外界直接訪問修改這個值,加private 
private static Student s = new Student(); 
// 提供公共的訪問方式
// 為了保證外界能夠直接使用該方法,加靜態 
public static Student getStudent() { return s; }}
public class StudentDemo { 
public static void main(String[] args) { 
// 通過單例得到對象
 Student s1 = Student.getStudent(); 
Student s2 = Student.getStudent(); 
System.out.println(s1 == s2); //true 
}
}

運行程序,控制臺會輸出true,說明我們用單例模式的餓漢式確保類在內存中只有一個對象,他的特點就是類一加載就創建對象,可以在代碼中Student類中體現到。那么我們怎樣才能在用這個對象的時候才去創建它呢,我們就要來看下懶漢式了。

懶漢式

  • 懶漢式:用對象的時候,才去創建對象
public class Teacher {
 private Teacher() { } 
private static Teacher t = null;
 public static Teacher getTeacher() {
 if (t == null) { 
t = new Teacher();//當我們去用這個對象的時候才去創建它 
} 
return t; 
}
}
public class TeacherDemo { 
public static void main(String[] args) { 
Teacher t1 = Teacher.getTeacher();
 Teacher t2 = Teacher.getTeacher(); 
System.out.println(t1 == t2); //true 
}
}

單例模式的餓漢式和懶漢式是不是很容易理解呢,那么我們什么時候用餓漢式什么時候用懶漢式呢?
我們就來總結一下

餓漢式懶漢式比較

餓漢式我們經常在開發中使用,因為餓漢式是不會出問題的單例模式
懶漢式我們在面試中回答用,因為懶漢式可能會出問題的單例模式。面試主要面兩個思想,分別是:

  • 懶加載思想(延遲加載)
  • 線程安全問題(就要考慮下面3個方面)
    • 是否多線程環境
    • b:是否有共享數據
    • c:是否有多條語句操作共享數據
      如果都是,就會存在線程的安全問題,我們上面的懶漢式代碼是不完整的,應該給對象中的方法加上synchronized關鍵字,這樣才算完整
public synchronized static Teacher getTeacher() { 
    if (t == null) { 
        t = new Teacher(); 
    } 
    return t;
}

Runtime類

我們在這里為什么要說Runtime類,因為它在java中的設計就是按照單例模式之餓漢式設計的,我們來看一段源碼

class Runtime { 
private Runtime() {} 
private static Runtime currentRuntime = new Runtime(); 
public static Runtime getRuntime() { 
return currentRuntime; 
}
}
  • 每個 Java 應用程序都有一個 Runtime 類實例,使應用程序能夠與其運行的環境相連接??梢酝ㄟ^ getRuntime 方法獲取當前運行時。
  • 應用程序不能創建自己的 Runtime 類實例。
  • Runtime類使用
    • public Process exec(String command)

這個類是用來干什么的呢,它可以幫助我們運行DOS命令,比如打開記事本、計算器之類的電腦工具,當然也有更多的功能,我們來體驗一下

public class RuntimeDemo { 
public static void main(String[] args) throws IOException { 
Runtime r = Runtime.getRuntime(); 
r.exec("notepad"); 
}
}

運行程序會幫我們打開記事本

r.exec("calc"); //換成calc,會幫我們打開計算機
r.exec("shutdown -s -t 1000");  // 這個命令會幫我們把電腦定時關機,上面的意思就是1000秒以后關機,我們來看運行后的效果圖 

模版設計模式

  • 模版設計模式概述
    • 模版方法模式就是定義一個算法的骨架,而將具體的算法延遲到子類中來實現
  • 優點
    • 使用模版方法模式,在定義算法骨架的同時,可以很靈活的實現具體的算法,滿足用戶靈活多變的需求
  • 缺點
    • 如果算法骨架有修改的話,則需要修改抽象類

我們可以在計算程序的運行時間中應用模版設計模式,在代碼中我們只需用改變要計算的代碼就可以了,把計算的時間設計成一個模版。

裝飾設計模式

  • 裝飾設計模式概述

    • 裝飾模式就是使用被裝飾類的一個子類的實例,在客戶端將這個子類的實例交給裝飾類。是繼承的替代方案
  • 優點

    • 使用裝飾模式,可以提供比繼承更靈活的擴展對象的功能,它可以動態的添加對象的功能,并且可以隨意的組合這些功能
  • 缺點

    • 正因為可以隨意組合,所以就可能出現一些不合理的邏輯
  • 在IO流中的裝飾模式應用

BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
BufferedWriter bw = new BufferedWriter((new OutputStreamWriter(System.out)));
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 設計模式匯總 一、基礎知識 1. 設計模式概述 定義:設計模式(Design Pattern)是一套被反復使用、多...
    MinoyJet閱讀 3,978評論 1 15
  • 1 單例模式的動機 對于一個軟件系統的某些類而言,我們無須創建多個實例。舉個大家都熟知的例子——Windows任務...
    justCode_閱讀 1,469評論 2 9
  • 一、設計模式的分類 總體來說設計模式分為三大類: 創建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者...
    RamboLI閱讀 772評論 0 1
  • CAReplicatorLayer是一個Layer容器,添加到容器上的子Layer可以復制若干份;可以設定子Lay...
    怪小喵閱讀 5,223評論 1 17
  • 下午的心理學課程臨時改成了一場沙龍。由師從德國海靈格大師的崔老師來為我們主持。 這場沙龍的主題叫做“愛的序位”,主...
    銳博Reborn閱讀 337評論 0 0