Java常用設計模式
設計模式是對某一類問題的最優解決方案,熟練使用設計模式可以有效提高我們的代碼質量和性能以及節省我們開發迭代過程中的工作量。
Java中通常我們人爲有23種設計模式,以下將列舉在開發中比較實用的幾種進行講解和分析。
單例模式
-
使用場景
當需要某個類僅存在一個實例
-
優點
更加方便快捷的訪問方式,節省不必要的性能開銷,便於管理。
-
思路
要保證僅存在一個實例就需要隱藏掉自身本來的構造方法,通常採用將構造方法私有化(private)來實現,再通過一個靜態方法來得到唯一實例,而實例是否唯一就需要在方法中自行編輯邏輯進行判斷。
-
示例
一般用法:這裏直接採用懶加載,即時加載實用性不高就不列舉了。
class SingleInstance private constructor() { companion object { private var instance: SingleInstance? = null fun getInstance(): SingleInstance { if (instance == null) { instance = SingleInstance() } return instance!! } } }
線程安全:規避了傳統同步方法影響性能的問題。
class SingleInstance private constructor() { companion object { private var instance: SingleInstance? = null fun getInstance(): SingleInstance { if (instance == null) { synchronized(instance as SingleInstance) { if (instance == null) { instance = SingleInstance() } } } return instance!! } } }
kotlin:原生的實現,使用
object
關鍵字進行聲明。object SingleInstance{}
工廠模式
-
使用場景
需要得到類的實例但不希望與該類形成耦合
需要得到類的實例但不知道該類具體有哪些子類 -
優點
與特定類解耦,不必關心所需對象的創建過程。
-
思路
其主要目的就是爲了規避類的具體構造過程實現解耦的目的,實現方式有非常多種,可以不一定按照標準的寫法進行設計,根據實際的需求,在節約開發成本的前提下有理即可。
-
示例
簡單工廠模式(靜態工廠模式):缺點結構固定,如要添加新產品需要重新編寫創造代碼,違背開閉原則。
class Car(val name: String) { fun getName() { System.out.print("name:$name") } } object Factory { fun createCar(name:String)=when(name){ "Benz"-> Car(name) "BMW"-> Car(name) else-> throw RuntimeException("") } }
工廠方法模式:即針對每個產品創建多個工廠對象,缺點整合性不高,會伴隨多個工廠類。
object BenzFactory { fun create() = Car("Benz") } object BmwFactory { fun create() = Car("BMW") }
抽象工廠模式:工廠方法模式的升級版,
internal interface IFactory { fun create(): Car } object BenzFactory : IFactory { override fun create() = Car("Benz") } object BmwFactory : IFactory { override fun create() = Car("BMW") }
建造者模式(Builder Pattern)
-
使用場景
需要創建一個構造複雜的對象時
-
優點
創建的流程結構清晰
根據不同的生成器生成特定屬性的對象
使用者無需瞭解對象的具體組件
如工廠模式一般,將生成對象進行解耦
滿足開閉合原理,便於增加新的生成條件 -
思路
建造者模式在我的理解裏就是一種讓代碼結構更加工整的工廠模式。在Android中最常見的實現有官方的
AlertDialog
,其構建的一般思路如下:- 以靜態內部類的形式存在於所需生成類中
- 持有外部類的實例的引用
- 編寫需要修改實例參數的對應方法
- 每個配置方法以Builder類本身作爲返回值
-
示例
class Card { fun setColor() { } fun setSize() { } companion object { class CardBuilder { private val card = Card() fun setColor(): CardBuilder { card.setColor() return this } fun setSize(): CardBuilder { card.setSize() return this } fun build() = card } } }
原型模式
-
使用場景
通過一個已經創建的對象獲得與其屬性相同的一個或更多對象
-
優點
當創建過程複雜時,可以提高效率
保存當前對象的狀態,類似於複製品,可以作爲記錄保存 -
思路
實現一個可以“克隆”自身必要屬性的接口,通過該接口生成一個和當前屬性完全一樣的新實例。Java中默認已經實現了該接口,即
Object.clone()
方法。 -
示例
interface Cloneable<T> { fun clone(): T } class Person(var sex: Int) : Cloneable<Person> { override fun clone(): Person { return Person(sex) } }
責任鏈模式
-
使用場景
一個請求可以被多個對象處理,希望程序在運行期間由多個對象串聯消化該請求的處理
-
優點
低耦合 可以任意指定處理者的先後順序 調用簡單,不需要編寫額外的判斷邏輯
-
思路
定義通用接口,接口中至少定義兩個方法,方法一用於獲得下個執行者的實例,方法二爲具體執行邏輯。
-
示例
interface Handler { fun handleRequest(n: Int): String fun setNextHandler(next: Handler) } class Handler1 : Handler { private var nextHandler: Handler? = null override fun handleRequest(n: Int): String { if (n < 0) { return "Handler1" } else { nextHandler?.let { return it.handleRequest(n) } } throw NullPointerException("") } override fun setNextHandler(next: Handler) { nextHandler = next } } class Handler2 : Handler { private var nextHandler: Handler? = null override fun handleRequest(n: Int): String { if (n in 1..10) { return "Handler2" } else { nextHandler?.let { return it.handleRequest(n) } } throw NullPointerException("") } override fun setNextHandler(next: Handler) { nextHandler = next } } class Handler3 : Handler { private var nextHandler: Handler? = null override fun handleRequest(n: Int): String { if (n in 11..100) { return "Handler3" } else { nextHandler?.let { return it.handleRequest(n) } } throw NullPointerException("") } override fun setNextHandler(next: Handler) { nextHandler = next } } fun main() { val handler1 = Handler1() val handler2 = Handler2() val handler3 = Handler3() handler1.setNextHandler(handler2) handler2.setNextHandler(handler3) handler1.handleRequest(-1) handler1.handleRequest(1) handler1.handleRequest(11) }
中介者模式
-
使用場景
多個對象之間需要進行數據交換
-
優點
低耦合,調用者不需要關心對象之間具體的交互邏輯 對象之間不用直接關聯,邏輯清晰
-
思路
中介者和交互對象需要互相持有對方的實例,交互對象中調用交互方法委託中介者去告知其他交互對象。
-
示例
//Mediator(抽象中介者) interface Mediator { fun contact(message: String, colleague: Colleague) } //Colleague(抽象同事類) abstract class Colleague(protected var name: String, protected var mediator: Mediator) { abstract fun sendMessage(message: String) abstract fun getMessage(message: String) } //ConcreteColleague(具體同事類) class ConcreteColleagueHR(name: String, mediator: Mediator) : Colleague(name, mediator) { override fun sendMessage(message: String) { mediator.contact(message, this) } override fun getMessage(message: String) { println("HR#$name#:$message") } } class ConcreteColleagueAndroidDeveloper(name: String, mediator: Mediator) : Colleague(name, mediator) { override fun sendMessage(message: String) { mediator.contact(message, this) } override fun getMessage(message: String) { println("Android Developer#$name#:$message") } } //ConcreteMediator(具體中介者) class ConcreteMediator : Mediator { var concreteColleagueHR: ConcreteColleagueHR? = null var concreteColleagueAndroidDeveloper: ConcreteColleagueAndroidDeveloper? = null override fun contact(message: String, colleague: Colleague) { if (colleague == concreteColleagueHR) { concreteColleagueAndroidDeveloper?.getMessage(message) } else { concreteColleagueHR?.getMessage(message) } } } fun main() { val mediator = ConcreteMediator() val hr = ConcreteColleagueHR("Google招聘專員", mediator) val ad = ConcreteColleagueAndroidDeveloper("屌絲開發者", mediator) mediator.concreteColleagueHR = hr mediator.concreteColleagueAndroidDeveloper = ad hr.sendMessage("Hi,你有意向來我們公司嗎?") ad.sendMessage("是Google開發Android嗎?") hr.sendMessage("yes!") ad.sendMessage("我願意!") }
裝飾者模式
-
使用場景
在不改變已有類屬性的前提下,動態地將責任追加到對象之上.
-
優點
拓展簡單,不需要對已經存在的類進行修改
健壯性強,適用面很廣
-
思路
簡單來說就是通過對已有對象的二次封裝來拓展新的能力
JDK中實現:IO Stream框架。
-
示例
很簡單就不額外寫了,詳情可看Stream源碼。
觀察者模式
-
使用場景
建立一種對象與對象之間的依賴關係,一個對象發生改變時將自動通知其他對象,其他對象將相應作出反應。
-
優點
一個被觀察者可以對應多個觀察者,而且這些觀察者之間可以沒有任何相互聯繫,可以根據需要增加和刪除觀察者,使得系統更易於擴展。
減少對象之間的耦合有利於系統的複用,但是同時設計師需要使這些低耦合度的對象之間能夠維持行動的協調一致,保證高度的協作。
-
思路
觀察者的宗旨就是建立單對象與多對象之間的依賴關係,多對象彼此之間不耦合,每次只需操作被觀察者對象,由它來通知其他所有觀察者對象。
其實從生活中來看,就像一個我們的聊天羣,羣主是被觀察者,羣成員是觀察者,我們需要向該羣宣佈一些事務,不必挨個去通知,只需要告知羣主,由羣主自行管理和通知其羣內所有成員。
-
示例
//抽象觀察者 interface Observer { void update(String state); } //具體觀察者 class ProgramMonkeyObserver implements Observer { @Override public void update(String state) { System.out.println("Programer look the SDK download process is: "+state); } } //抽象被觀察者 abstract class Subject { private List<Observer> list = new ArrayList<>(); public void attach(Observer observer) { list.add(observer); } public void detach(Observer observer) { list.remove(observer); } public void motifyObservers(String newState) { for (Observer observer : list) { observer.update(newState); } } } //具體被觀察者 class SDKDownloadSubject extends Subject { public void netProcessChange(String data) { this.motifyObservers(data); } }
模板模式
-
使用場景
已知一套算法流程,具體步驟實現不同,但是大致的執行順序相同,爲了避免多次重新編寫邏輯,定義一個算法骨架,每次只需要實現具體每步步驟即可。
-
優點
節省工作量,提高代碼複用能力
便於維護和梳理業務邏輯
-
思路
模板模式其實但凡對代碼質量有一定要求的人都肯定有用過,只是不知道這已經被前人歸納成爲了設計模式而已。
最常見使用方式是在業務類中,定義一個抽象基類,該類中定義好業務所需的所有步驟的方法,可不實現,最後在一個方法中將所有定義好的步驟按照需要的流程順序進行調用。
-
示例
以程序猿的一天爲例( ⊙ o ⊙ ):
abstract class Monkey{ abstract fun getUp() abstract fun eat() abstract fun goToWork() abstract fun coding() abstract fun goToHome() abstract fun sleep() fun datStart() { getUp() eat() goToWork() coding() eat() coding() goToHome() eat() sleep() } }
-