JAVA基礎再回首(二十六)——面向對象思想設計原則、設計模式、簡單工廠模式、工廠方法模式、單例設計模式之餓漢式和懶漢式、Runtime類
版權聲明:轉載必須注明本文轉自程式員杜鵬程的部落格:http://blog.csdn.net/m366917
這篇我們來學習面向對象思想設計原則及常見的設計模式
面向對象思想設計原則
在實際的開發中,我們要想更深入的了解面向對象思想,就必須熟悉前人總結過的面向對象的思想的設計原則,那麼都有哪些原則呢,我們就來了解一下
- 單一職責原則
- 其實就是開發人員經常說的”高内聚,低耦合”
- 開閉原則
- 核心思想是:一個對象對擴充開放,對修改關閉。其實開閉原則的意思就是:對類的改動是通過增加代碼進行的,而不是修改現有代碼。
- 裡氏替換原則
- 核心思想:在任何父類出現的地方都可以用它的子類來替代。其實就是說:同一個繼承體系中的對象應該有共同的行為特征。
- 依賴注入原則
- 核心思想:要依賴于抽象,不要依賴于具體實作。
- 接口分離原則
- 核心思想:不應該強迫程式依賴它們不需要使用的方法。
- 迪米特原則
- 核心思想:一個對象應當對其他對象盡可能少的了解
這些原則呢,我們在平時開發中可以用到,做一些大一點的項目,就要考慮用到這些思想,下面,我簡單的介紹一下這些原則的核心思想,大家做以了解,如果要将這些原則運用到自己項目中,還要自己更加深入的學習、了解、運用。
- 核心思想:一個對象應當對其他對象盡可能少的了解
設計模式
設計模式在我們開發中還是經常用到的,那麼,下面我們來學習一下
- 設計模式概述
- 設計模式(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("shutdown -s -t 1000");
這個指令會幫我們把電腦定時關機,上面的意思就是1000秒以後關機,我們來看運作後的效果圖 那麼怎麼取消呢?
r.exec("shutdown -a");
哈哈,這樣就取消了
下面我們來說說模版設計模式和裝飾設計模式,這個大家作為了解,想要深入學習的話,可以在網上查閱相關的資料進行學習
模版設計模式
- 模版設計模式概述
- 模版方法模式就是定義一個算法的骨架,而将具體的算法延遲到子類中來實作
- 優點
- 使用模版方法模式,在定義算法骨架的同時,可以很靈活的實作具體的算法,滿足使用者靈活多變的需求
- 缺點
- 如果算法骨架有修改的話,則需要修改抽象類
我們可以在計算程式的運作時間中應用模版設計模式,在代碼中我們隻需用改變要計算的代碼就可以了,把計算的時間設計成一個模版。
裝飾設計模式
- 裝飾設計模式概述
- 裝飾模式就是使用被裝飾類的一個子類的執行個體,在用戶端将這個子類的執行個體交給裝飾類。是繼承的替代方案
- 優點
- 使用裝飾模式,可以提供比繼承更靈活的擴充對象的功能,它可以動态的添加對象的功能,并且可以随意的組合這些功能
- 缺點
- 正因為可以随意組合,是以就可能出現一些不合理的邏輯
在IO流中的裝飾模式應用
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter((new OutputStreamWriter(System.out)));
好了,我們設計模式就将這麼多了,最後呢,我上傳一本書《java與模式》有興趣的你可以下載下傳看看
歡迎有興趣的同學加我朋友的QQ群:點選直接加群555974449 請備注:java基礎再回首我們一起來玩吧。