感覺設計模式是看著簡單 ,但是一用就不會,23種設計模式,學的人頭大,相信大家都是這樣的
設計模式在程序員的面試中會被考到,通常是介紹其原理并說出優(yōu)缺點?;蛘邔Ρ葞讉€比較相似的模式的異同點。在筆試中可能會出現(xiàn)畫出某個設計模式的UML圖這樣的題。雖說面試中占的比重不大,但并不代表它不重要。恰恰相反,設計模式于程序員而言相當重要,它是我們寫出優(yōu)秀程序的保障。設計模式與程序員的架構能力與閱讀源碼的能力息息相關,非常值得我們深入學習。
面向對象的威力從這個小例子中只能看到冰山一角,好比一段兩公里的路程,坐飛機和走路花費的時間差不了多少。但當我們需要翻山越嶺、漂洋過海時,坐飛機的人就會將走路的人遠遠拋在后面。 面向對象的特點是可維護、可復用、可擴展、靈活性好,它真正強大的地方在于:隨著業(yè)務變得越來越復雜,面向對象依然能夠使得程序結構良好,而面向過程卻會導致程序越來越臃腫。 讓面向對象保持結構良好的秘訣就是 設計模式。
熟練掌握各種設計模式,并能在實際編程開發(fā)中靈活運用它們,不僅能使代碼更規(guī)范,重用性更高,同時也能保證代碼的可靠性,提高開發(fā)效率。這段時間又系統(tǒng)看了設計模式的相關內(nèi)容,
總體來說設計模式分為三大類:(本文著重講解標紅) 二.七個設計原則面向對象編程有七大原則,即經(jīng)常提到的Design Pattern,提倡它的根本原因是為了代碼復用,增加可維護性。設計模式就是實現(xiàn)了這些原則,從而達到了代碼復用、增加可維護性的目的。
因為設計模式就是基于這些原則的實現(xiàn),所以很有必要了解這些原則,下面主要對面向對象編程的幾個原則進行簡單介紹。 1、單一職責原則 ( SRP )英文全稱是Single Responsibility Principle,定義是一個類,應該只有一個引起它變化的原因。類變化的原因就是職責,如果一個類承擔的職責過多,就等于把這些職責耦合在一起了。一個職責的變化可能會削弱或者抑制這個類完成其他職責的能力。這種耦合會導致脆弱的設計,當發(fā)生變化時,設計會遭受到意想不到的破壞。而如果想要避免這種現(xiàn)象的發(fā)生,就要盡可能的遵守單一職責原則。此原則的核心就是解耦和增強內(nèi)聚性。
創(chuàng)建型模式是指這些設計模式提供了一種在創(chuàng)建對象的同時隱藏創(chuàng)建邏輯的方式,而不是使用新的運算符直接實例化對象。這使得程序在判斷針對某個給定實例需要創(chuàng)建哪些對象時更加靈活
1.單例模式
確保某一個類只有一個實例,并自行實例化向整個系統(tǒng)提供這個實例。
單例模式理解起來不難,典型例子有一個公司只能有一個CEO。它主要是為了保證一個類僅有一個實例,這個類中自己提供一個返回實例的方法,方法中先判斷系統(tǒng)是否已經(jīng)有這個單例,如果有則返回,如果沒有則創(chuàng)建。如果創(chuàng)建多個實例會消耗過多的資源或者某種類型的對象只應該有且只有一個時,應該考慮使用單例模式。
單例模式理解起來不難,重要的是需要掌握它的幾種常見寫法。 public class Singleton { // 直接創(chuàng)建對象 public static Singleton instance = new Singleton(); // 私有化構造函數(shù) private Singleton() { } // 返回對象實例 public static Singleton getInstance() { return instance; } }
//寫法一、懶漢式寫法 public class Singleton { private static Singleton instance; //構造函數(shù)私有 private Singleton (){ } public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } //寫法二、DCL(Double Check Lock) 雙重校驗鎖 public class Singleton { private volatile static Singleton singleton; private Singleton (){ } public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } } //寫法三、靜態(tài)內(nèi)部類單例模式 public class Singleton { private Singleton (){ } public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } }
2.工廠方法模式
定義一個用于創(chuàng)建對象的接口,讓子類決定實例化哪一個類。 工廠方法模式分為三種:普通工廠模式,就是建立一個工廠類,對實現(xiàn)了同一接口的一些類進行實例的創(chuàng)建。多個工廠方法模式,是對普通工廠方法模式的改進,在普通工廠方法模式中,如果傳遞的字符串出錯,則不能正確創(chuàng)建對象,而多個工廠方法模式是提供多個工廠方法,分別創(chuàng)建對象。靜態(tài)工廠方法模式,將上面的多個工廠方法模式里的方法置為靜態(tài)的,不需要創(chuàng)建實例,直接調用即可 . (1)普通工廠模式 public interface Sender { public void Send(); } public class MailSender implements Sender { @Override public void Send() { System.out.println("this is mail sender!"); } } public class SmsSender implements Sender { @Override public void Send() { System.out.println("this is sms sender!"); } } public class SendFactory { public Sender produce(String type) { if ("mail".equals(type)) { return new MailSender(); } else if ("sms".equals(type)) { return new SmsSender(); } else { System.out.println("請輸入正確的類型!"); return null; } } }
(2)多個工廠模式 該模式是對普通工廠方法模式的改進,在普通工廠方法模式中,如果傳遞的字符串出錯,則不能正確創(chuàng)建對象,而多個工廠方法模式是提供多個工廠方法,分別創(chuàng)建對象。 public class SendFactory { public Sender produceMail(){ return new MailSender(); } public Sender produceSms(){ return new SmsSender(); } } public class FactoryTest { public static void main(String[] args) { SendFactory factory = new SendFactory(); Sender sender = factory.produceMail(); sender.send(); } }
(3)靜態(tài)工廠模式 靜態(tài)工廠方法模式,將上面的多個工廠方法模式里的方法置為靜態(tài)的,不需要創(chuàng)建實例,直接調用即可 public class SendFactory { public static Sender produceMail(){ return new MailSender(); } public static Sender produceSms(){ return new SmsSender(); } } public class FactoryTest { public static void main(String[] args) { Sender sender = SendFactory.produceMail(); sender.send(); } }
3.抽象工廠模式工廠方法模式有一個問題就是,類的創(chuàng)建依賴工廠類,也就是說,如果想要拓展程序,必須對工廠類進行修改,這違背了閉包原則,所以,從設計角度考慮,有一定的問題,如何解決?就用到抽象工廠模式,創(chuàng)建多個工廠類,這樣一旦需要增加新的功能, 直接增加新的工廠類就可以了,不需要修改之前的代碼。 代碼還是在工廠方法模式的基礎上改進 public interface Provider { public Sender produce(); } ---------------------------------------------------------------------------- public interface Sender { public void send(); } ---------------------------------------------------------------------------- public class MailSender implements Sender { @Override public void send() { System.out.println("this is mail sender!"); } } --------------------------------------------------------------------------- public class SmsSender implements Sender { @Override public void send() { System.out.println("this is sms sender!"); } } --------------------------------------------------------- public class SendSmsFactory implements Provider { @Override public Sender produce() { return new SmsSender(); } } public class SendMailFactory implements Provider { @Override public Sender produce() { return new MailSender(); } } ------------------------------------------------------------- public class Test { public static void main(String[] args) { Provider provider = new SendMailFactory(); Sender sender = provider.produce(); sender.send(); } }
4.建造者模式(Builder )工廠類模式提供的是創(chuàng)建單個類的模式,而建造者模式則是將各種產(chǎn)品集中起來進行管理,用來創(chuàng)建復合對象,所謂復合對象就是指某個類具有不同的屬性,其實建造者模式就是前面抽象工廠模式和最后的 Test 結合起來得到的 public class Builder { private List<Sender> list = new ArrayList<Sender>(); public void produceMailSender(int count) { for (int i = 0; i < count; i++) { list.add(new MailSender()); } } public void produceSmsSender(int count) { for (int i = 0; i < count; i++) { list.add(new SmsSender()); } } } public class TestBuilder { public static void main(String[] args) { Builder builder = new Builder(); builder.produceMailSender(10); } }
5.原型模式
用原型實例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象。
原型模式不難理解,它主要是用在實例創(chuàng)建的時候,因為有的時候我們通過new創(chuàng)建一個對象時可能成本過高,這時我們可以考慮直接通過直接克隆實例快速創(chuàng)建對象??寺『蟮膶嵗c原實例內(nèi)部屬性一致。原型模式需要注意一個深拷貝和淺拷貝的問題。
1.適配器設計模式適配器模式將某個類的接口轉換成客戶端期望的另一個接口表示,目的是消除由于接口不匹配所造成的類的兼容性問題。主要分為三類:類的適配器模式、對象的適配器模式、接口的適配器模式
public class Source { public void method1() { System.out.println("this is original method!"); } } ------------------------------------------------------------- public interface Targetable { /* 與原類中的方法相同 */ public void method1(); /* 新類的方法 */ public void method2(); } public class Adapter extends Source implements Targetable { @Override public void method2() { System.out.println("this is the targetable method!"); } } public class AdapterTest { public static void main(String[] args) { Targetable target = new Adapter(); target.method1(); target.method2(); } }
基本思路和類的適配器模式相同,只是將 Adapter 類作修改,這次不繼承 Source 類,而是持有 Source 類的實例,以達到解決兼容性的問題 public class Wrapper implements Targetable { private Source source; public Wrapper(Source source) { super(); this.source = source; } @Override public void method2() { System.out.println("this is the targetable method!"); } @Override public void method1() { source.method1(); } } -------------------------------------------------------------- public class AdapterTest { public static void main(String[] args) { Source source = new Source(); Targetable target = new Wrapper(source); target.method1(); target.method2(); } }
接口的適配器是這樣的:有時我們寫的一個接口中有多個抽象方法,當我們寫該接口的實現(xiàn)類時,必須實現(xiàn)該接口的所有方法,這明顯有時比較浪費,因為并不是所有的方法都是我們需要的,有時只需要某一些,此處為了解決這個問題,我們引入了接口的適配器模式,借助于一個抽象類,該抽象類實現(xiàn)了該接口,實現(xiàn)了所有的方法,而我們不和原始的接口打交道,只和該抽象類取得聯(lián)系,所以我們寫一個類,繼承該抽象類,重寫我們需要的方法就行。 2.橋接模式
將抽象部分與實現(xiàn)部分分離,使它們都可以獨立的變化。
在軟件系統(tǒng)中,某些類型由于自身的邏輯,它具有兩個或多個維度的變化,那么如何應對這種“多維度的變化”?這就要使用橋接模式。橋接模式需要重點理解的抽象部分,實現(xiàn)部分,脫耦。一個典型的例子是咖啡加糖問題,抽象部分有Coffee,其下有LargeCoffee,SmallCoffee,實現(xiàn)部分是CoffeeAdd,其下有Sugar,Normal,抽象類Coffee中引用CoffeeAdd,這樣CoffeeAdd其實就是一個橋接。
將對象組合成樹形結構以表示“部分-整體”的層次結構,使得用戶對單個對象和組合對象的使用具有一致性。
組合模式理解起來相對簡單,典型的例子就是假設公司A,里面有不同的部門,不同的部分下有不同的員工,這樣一個部門下的所有員工組合成了一個部門,所有部門組合成了整個公司。
為子系統(tǒng)中的一組接口提供一個一致的界面,外觀模式定義了一個高層接口,這個接口使得這一子系統(tǒng)更加容易使用。
外觀模式的一個典型例子是去醫(yī)院看病,掛號、門診、劃價、取藥,讓患者或患者家屬覺得很復雜,如果有提供接待人員,只讓接待人員來處理,就很方便。
運用共享技術有效地支持大量細粒度的對象。
在有大量對象時,有可能會造成內(nèi)存溢出,我們把其中共同的部分抽象出來,如果有相同的業(yè)務請求,直接返回在內(nèi)存中已有的對象,避免重新創(chuàng)建。
為其他對象提供一種代理以控制對這個對象的訪問。
代理模式主要解決在直接訪問對象時帶來的問題。舉個例子,豬八戒去找高翠蘭結果是孫悟空變的,可以這樣理解:把高翠蘭的外貌抽象出來,高翠蘭本人和孫悟空都實現(xiàn)了這個接口,豬八戒訪問高翠蘭的時候看不出來這個是孫悟空,所以說孫悟空是高翠蘭代理類。
1.模板方法模式
一個操作中的算法的框架,而將一些步驟延遲到子類中,使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。
模板方法模式一個典型例子就是Android中的異步任務類AsyncTask,它對異步任務的執(zhí)行進行了流程封裝,子類繼承它時,只需在指定的流程中實現(xiàn)具體的操作即可。
將一個請求封裝為一個對象,從而可用不同的請求對客戶進行參數(shù)化;對請求排隊或記錄請求日志,以及支持可取消的操作
命令模式主要是通過調用者調用接受者執(zhí)行命令,這個模式中需要理解的是三個角色:(1) Receiver 真正的命令執(zhí)行對象 (2) Command 持有一個對Receiver的引用,調用Receiver的相關方法。(3) Invoker 請求者,持有一個對Command的引用,調用Command的方法執(zhí)行具體命令。
提供一種方法順序訪問一個聚合對象中各個元素, 而又不需暴露該對象的內(nèi)部表示。
在Java集合框架中我們知道對于一個指定的集合類,我們可以使用一個特定的Iterator迭代器來對集合中的所有元素進行遍歷。這樣結合來看,迭代器模式很好理解了。
定義對象間的一種一對多的依賴關系,當一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并被自動更新。
觀察者模式可以結合Android中的ListView來理解,ListView關聯(lián)的適配器Adapter在數(shù)據(jù)發(fā)生變化時會通過notifyDataSetChanged()方法來通知界面刷新。
用一個中介對象來封裝一系列的對象交互。中介者使各對象不需要顯式地相互引用,從而使其耦合松散,而且可以獨立地改變它們之間的交互。
中介者模式的典型例子就是未加入 WTO 之前各個國家相互貿(mào)易,結構復雜,大家都加入WTO后是各個國家通過 WTO 來互相貿(mào)易,變得規(guī)范。
在不破壞封裝性的前提下,捕獲一個對象的內(nèi)部狀態(tài),并在該對象之外保存這個狀態(tài)。這樣以后就可將該對象恢復到保存的狀態(tài)。
備忘錄模式的典型例子就是git版本管理工具,它幫我們保存了每次提交后的項目狀態(tài),在必要的時候我們可以回退到指定的版本中。
給定一個語言,定義它的文法的一種表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。
解釋器的典型例子是在編譯原理中的應用,如果一種特定類型的問題發(fā)生的頻率足夠高,那么可能就值得將該問題的各個實例表述為一個簡單語言中的句子。這樣就可以構建一個解釋器,該解釋器通過解釋這些句子來解決該問題。
允許一個對象在其內(nèi)部狀態(tài)改變時改變它的行為。對象看起來似乎修改了它的類。
狀態(tài)模式主要解決對象的行為依賴于它的狀態(tài)(屬性),并且可以根據(jù)它的狀態(tài)改變而改變它的相關行為。典型的例子是一個人在不同的狀態(tài)下完成一件事的結果可能是不同的。
定義一系列的算法,把它們一個個封裝起來, 并且使它們可相互替換。本模式使得算法可獨立于使用它的客戶而變化。
從策略模式的定義可以看到它主要是將算法和客戶獨立開,一個典型的例子是排序算法,我們給定一個數(shù)組,輸出排序后的結果,但是過程中我們可以采取不同的排序算法,這些算法其實就是策略。
使多個對象都有機會處理請求,從而避免請求的發(fā)送者和接收者之間的耦合關系。將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它為止。
責任鏈模式,避免請求發(fā)送者與接收者耦合在一起,讓多個對象都有可能接收請求,將這些對象連接成一條鏈,并且沿著這條鏈傳遞請求,直到有對象處理它為止。
封裝一些作用于某種數(shù)據(jù)結構中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。
訪問者模式是一種將數(shù)據(jù)操作和數(shù)據(jù)結構分離的設計模式,它通常使用在對象結構比較穩(wěn)定,但是經(jīng)常需要在此對象結構上定義新的操作,或者需要對一個對象結構中的對象進行很多不同的并且不相關的操作,而需要避免讓這些操作"污染"這些對象的類,使用訪問者模式將這些封裝到類中
到這里,Java設計模式的學習總結就結束了,因為個人能力有限,有些模式只是簡單介紹了一下,想要進一步學習的話還是要靠大家自己去查閱相關資料學習。熟練地掌握設計模式,還需多多的實踐.
有完整的Java初級,高級對應的學習路線和資料!專注于java開發(fā)。分享java基礎、原理性知識、JavaWeb實戰(zhàn)、spring全家桶、設計模式、分布式及面試資料、開源項目,助力開發(fā)者成長!
|
|