Java設計模式學習

一.概述

熟練掌握各類設計模式,並能在實際編程開發中靈活運用它們,不只能使代碼更規範,重用性更高,同時也能保證代碼的可靠性,提升開發效率。這段時間又系統看了設計模式的相關內容,
整理學習總結以下:
html

  • 七個設計原則
  • 建立型模式(5種)
  • 結構型模式(7種)
  • 行爲型模式(11種)

整體來講設計模式分爲三大類:(本文着重講解標紅)
建立型模式,共五種: 工廠方法模式抽象工廠模式單例模式建造者模式、原型模式。
結構型模式,共七種: 適配器模式、裝飾器模式、 代理模式、外觀模式、橋接模式、組合模式、 享元模式
行爲型模式,共十一種: 策略模式、模板方法模式、 觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。
git

二.七個設計原則

面向對象編程有七大原則,即常常提到的Design Pattern,提倡它的根本緣由是爲了代碼複用,增長可維護性。設計模式就是實現了這些原則,從而達到了代碼複用、增長可維護性的目的。算法

由於設計模式就是基於這些原則的實現,因此頗有必要了解這些原則,下面主要對面向對象編程的幾個原則進行簡單介紹。編程

 一、單一職責原則 ( SRP )

英文全稱是Single Responsibility Principle,定義是一個類,應該只有一個引發它變化的緣由。類變化的緣由就是職責,若是一個類承擔的職責過多,就等於把這些職責耦合在一塊兒了。一個職責的變化可能會削弱或者抑制這個類完成其餘職責的能力。這種耦合會致使脆弱的設計,當發生變化時,設計會遭受到意想不到的破壞。而若是想要避免這種現象的發生,就要儘量的遵照單一職責原則。此原則的核心就是解耦和加強內聚性。設計模式

二、開閉原則 ( OCP )

英文全稱是Open Close Principle,定義是軟件實體(包括類、模塊、函數等)應該對於擴展時開放的,對於修改是封閉的。開閉原則是是面向對象設計中最重要的原則之一,其它不少的設計原則都是實現開閉原則的一種手段。數組

三、里氏替換原則 ( LSP )

英文全稱是Liskov Substitution Principle,是面向對象設計的基本原則之一。 定義是任何基類能夠出現的地方,子類必定能夠出現。LSP 是繼承複用的基石,只有當派生類能夠替換掉基類,且軟件單位的功能不受到影響時,基類才能真正被複用,而派生類也可以在基類的基礎上增長新的行爲。里氏替換原則是對開閉原則的補充。實現開閉原則的關鍵步驟就是抽象化,而基類與子類的繼承關係就是抽象化的具體實現,因此里氏替換原則是對實現抽象化的具體步驟的規範。安全

四、依賴倒置原則 ( DIP )

英文全稱是Dependence Inversion Principle,這個原則是開閉原則的基礎,依賴倒置原則就是要求調用者和被調用者都依賴抽象,這樣二者沒有直接的關聯和接觸,在變更的時候,一方的變更不會影響另外一方的變更。依賴倒置強調了抽象的重要性,針對接口編程,依賴於抽象而不依賴於具體。數據結構

五、接口隔離原則 ( ISP )

英文全稱是Interface Segregation Principle,這個原則的意思是使用多個隔離的接口,比使用單個接口要好。目的就是下降類之間的耦合度,便於軟件升級和維護。閉包

六、最少知道原則(迪米特原則)

一個實體應當儘可能少地與其餘實體之間發生相互做用,使得系統功能模塊相對獨立。通俗地說就是不要和陌生人說話,即一個對象應對其餘對象有儘量少的瞭解。迪米特法則的初衷在於下降類之間的耦合。因爲每一個類儘可能減小對其餘類的依賴,所以,很容易使得系統的功能模塊功能獨立,相互之間不存在(或不多有)依賴關係。併發

七、合成/聚合複用(CARP)

英文全稱是Composite Reuse Principle,合成/聚合複用原則常常又叫作合成複用原則。合成/聚合複用原則的潛臺詞是:我只是用你的方法,咱們不必定是同類。繼承的耦合性更大,好比一個父類後來添加實現一個接口或者去掉一個接口,那子類可能會遭到毀滅性的編譯錯誤,但若是隻是組合聚合,只是引用類的方法,就不會有這種巨大的風險,同時也實現了複用。

三.建立者模式(5種)

 

 建立型模式是指這些設計模式提供了一種在建立對象的同時隱藏建立邏輯的方式,而不是使用新的運算符直接實例化對象。這使得程序在判斷針對某個給定實例須要建立哪些對象時更加靈活

 

1.單例模式

  • 定義

確保某一個類只有一個實例,並自行實例化向整個系統提供這個實例。

  • 簡介

單例模式理解起來不難,典型例子有一個公司只能有一個CEO。它主要是爲了保證一個類僅有一個實例,這個類中本身提供一個返回實例的方法,方法中先判斷系統是否已經有這個單例,若是有則返回,若是沒有則建立。若是建立多個實例會消耗過多的資源或者某種類型的對象只應該有且只有一個時,應該考慮使用單例模式。

  • 實現

單例模式理解起來不難,重要的是須要掌握它的幾種常見寫法。

餓漢式:
public class Singleton {
// 直接建立對象
public static Singleton instance = new Singleton();
// 私有化構造函數
private Singleton() {
}
// 返回對象實例
public static Singleton getInstance() {
return instance;
}
}
View Code

懶漢式:

//寫法1、懶漢式寫法

public class Singleton {
 
    private static Singleton instance; 

    //構造函數私有
    private Singleton (){
    }  

    public static synchronized Singleton getInstance() { 
         if (instance == null) {  
             instance = new Singleton();  
         }  
         return instance;  
    }  
}  
寫法一

//寫法1、懶漢式寫法

public class Singleton {
 
    private static Singleton instance; 

    //構造函數私有
    private Singleton (){
    }  

    public static synchronized Singleton getInstance() { 
         if (instance == null) {  
             instance = new Singleton();  
         }  
         return instance;  
    }  
} 
//寫法2、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;  
    }  
} 
寫法二
//寫法3、靜態內部類單例模式

public class Singleton {  

    private Singleton (){
    }  

    public static final Singleton getInstance() {  
          return SingletonHolder.INSTANCE;  
    }  

    private static class SingletonHolder {  
         private static final Singleton INSTANCE = new Singleton();  
    }
}   
寫法三
上面的第一種懶漢式寫法作到了延遲建立和線程安全,缺點是每次調用getInstance()時都必須進行同步,效率不佳。第二種DCL方式比較常見,兩次判空,第一次判空避免了沒必要要的同步,第二次保證了單例建立,這種方式比較不錯,可是在高併發環境下有時會出現問題。第三種方法最被推薦,線程安全也保證了實例惟一。

2.工廠方法模式

  • 定義

定義一個用於建立對象的接口,讓子類決定實例化哪個類。

工廠方法模式分爲三種:普通工廠模式,就是創建一個工廠類,對實現了同一接口的一些類進行實例的建立。多個工廠方法模式,是對普通工廠方法模式的改進,在普通工廠方法模式中,若是傳遞的字符串出錯,則不能正確建立對象,而多個工廠方法模式是提供多個工廠方法,分別建立對象。靜態工廠方法模式,將上面的多個工廠方法模式裏的方法置爲靜態的,不須要建立實例,直接調用便可 .

(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;
}
}
}
View Code

(2)多個工廠模式

該模式是對普通工廠方法模式的改進,在普通工廠方法模式中,若是傳遞的字符串出錯,則不能正確建立對象,而多個工廠方法模式是提供多個工廠方法,分別建立對象。

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;
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();
}
}
View Code

(3)靜態工廠模式

靜態工廠方法模式,將上面的多個工廠方法模式裏的方法置爲靜態的,不須要建立實例,直接調用便可

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();
}
}
View Code

3.抽象工廠模式

工廠方法模式有一個問題就是,類的建立依賴工廠類,也就是說,若是想要拓展程序,必須對工廠類進行修改,這違背了閉包原則,因此,從設計角度考慮,有必定的問題,如何解決?就用到抽象工廠模式,建立多個工廠類,這樣一旦須要增長新的功能, 直接增長新的工廠類就能夠了,不須要修改以前的代碼。

代碼仍是在工廠方法模式的基礎上改進

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();
}
}
View Code

4.建造者模式(Builder )

工廠類模式提供的是建立單個類的模式,而建造者模式則是將各類產品集中起來進行管理,用來建立複合對象,所謂複合對象就是指某個類具備不一樣的屬性,其實建造者模式就是前面抽象工廠模式和最後的 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());
}
}
}
View Code
public class TestBuilder {
public static void main(String[] args) {
Builder builder = new Builder();
builder.produceMailSender(10);
}
}
View Code

5.原型模式

  • 定義

用原型實例指定建立對象的種類,而且經過拷貝這些原型建立新的對象。

  • 簡介

原型模式不難理解,它主要是用在實例建立的時候,由於有的時候咱們經過new建立一個對象時可能成本太高,這時咱們能夠考慮直接經過直接克隆實例快速建立對象。克隆後的實例與原實例內部屬性一致。原型模式須要注意一個深拷貝和淺拷貝的問題。

四.結構型模式(7種)

結構型模式關注類和對象的組合。繼承的概念被用來組合接口和定義組合對象得到新功能的方式。

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();
 }
}
View Code
  • 對象的適配器模式

基本思路和類的適配器模式相同,只是將 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();
}
}
View Code
  • 接口的適配器模式

接口的適配器是這樣的:有時咱們寫的一個接口中有多個抽象方法,當咱們寫該接口的實現類時,必須實現該接口的全部方法,這明顯有時比較浪費,由於並非全部的方法都是咱們須要的,有時只須要某一些,此處爲了解決這個問題,咱們引入了接口的適配器模式,藉助於一個抽象類,該抽象類實現了該接口,實現了全部的方法,而咱們不和原始的接口打交道,只和該抽象類取得聯繫,因此咱們寫一個類,繼承該抽象類,重寫咱們須要的方法就行。

 2.橋接模式

  • 定義

將抽象部分與實現部分分離,使它們均可以獨立的變化。

  • 簡介

在軟件系統中,某些類型因爲自身的邏輯,它具備兩個或多個維度的變化,那麼如何應對這種「多維度的變化」?這就要使用橋接模式。橋接模式須要重點理解的抽象部分,實現部分,脫耦。一個典型的例子是咖啡加糖問題,抽象部分有Coffee,其下有LargeCoffee,SmallCoffee,實現部分是CoffeeAdd,其下有Sugar,Normal,抽象類Coffee中引用CoffeeAdd,這樣CoffeeAdd其實就是一個橋接。查看更多

3.裝飾模式

顧名思義,裝飾模式就是給一個對象增長一些新的功能,並且是動態的,要求裝飾對象和被裝飾對象實現同一個 接口,裝飾對象持有被裝飾對象的實例。

public interface Sourceable {
public void method();
}
----------------------------------------------------
public class Source implements Sourceable {
@Override
public void method() {
System.out.println("the original method!");
}
}
 ----------------------------------------------------
 public class Decorator implements Sourceable {
 private Sourceable source;
 public Decorator(Sourceable source) {
 super();
 this.source = source;
 }
 @Override
 public void method() {
 System.out.println("before decorator!");
 source.method();
 System.out.println("after decorator!");
 }
 }
 ----------------------------------------------------
 public class DecoratorTest {
 public static void main(String[] args) {
 Sourceable source = new Source();
 Sourceable obj = new Decorator(source);
 obj.method();
 }
 }
View Code

4.組合模式

  • 定義

將對象組合成樹形結構以表示「部分-總體」的層次結構,使得用戶對單個對象和組合對象的使用具備一致性。

  • 簡介

組合模式理解起來相對簡單,典型的例子就是假設公司A,裏面有不一樣的部門,不一樣的部分下有不一樣的員工,這樣一個部門下的全部員工組合成了一個部門,全部部門組合成了整個公司。

5.外觀模式

  • 定義

爲子系統中的一組接口提供一個一致的界面,外觀模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。

  • 簡介

外觀模式的一個典型例子是去醫院看病,掛號、門診、劃價、取藥,讓患者或患者家眷以爲很複雜,若是有提供接待人員,只讓接待人員來處理,就很方便。點擊查看更多

6.享元模式

  • 定義

運用共享技術有效地支持大量細粒度的對象。

  • 簡介

在有大量對象時,有可能會形成內存溢出,咱們把其中共同的部分抽象出來,若是有相同的業務請求,直接返回在內存中已有的對象,避免從新建立。點擊查看更多

7.代理模式

  • 定義

爲其餘對象提供一種代理以控制對這個對象的訪問。

  • 簡介

代理模式主要解決在直接訪問對象時帶來的問題。舉個例子,豬八戒去找高翠蘭結果是孫悟空變的,能夠這樣理解:把高翠蘭的外貌抽象出來,高翠蘭本人和孫悟空都實現了這個接口,豬八戒訪問高翠蘭的時候看不出來這個是孫悟空,因此說孫悟空是高翠蘭代理類。點擊查看更多

5、行爲型模式 ( 11種 )

這些設計模式特別關注對象之間的通訊。

1.模板方法模式

  • 定義

一個操做中的算法的框架,而將一些步驟延遲到子類中,使得子類能夠不改變一個算法的結構便可重定義該算法的某些特定步驟。

  • 例子

模板方法模式一個典型例子就是Android中的異步任務類AsyncTask,它對異步任務的執行進行了流程封裝,子類繼承它時,只需在指定的流程中實現具體的操做便可。點擊查看更多關於模板方法模式的介紹

2.命令模式

  • 定義

將一個請求封裝爲一個對象,從而可用不一樣的請求對客戶進行參數化;對請求排隊或記錄請求日誌,以及支持可取消的操做

  • 簡介

命令模式主要是經過調用者調用接受者執行命令,這個模式中須要理解的是三個角色:(1) Receiver 真正的命令執行對象 (2) Command 持有一個對Receiver的引用,調用Receiver的相關方法。(3) Invoker 請求者,持有一個對Command的引用,調用Command的方法執行具體命令。點擊查看更多關於命令模式的介紹

3.迭代器模式

  • 定義

提供一種方法順序訪問一個聚合對象中各個元素, 而又不需暴露該對象的內部表示。

  • 簡介

在Java集合框架中咱們知道對於一個指定的集合類,咱們可使用一個特定的Iterator迭代器來對集合中的全部元素進行遍歷。這樣結合來看,迭代器模式很好理解了。點擊查看更多

4.觀察者模式

  • 定義

定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,全部依賴於它的對象都獲得通知並被自動更新。

  • 簡介

觀察者模式能夠結合Android中的ListView來理解,ListView關聯的適配器Adapter在數據發生變化時會經過notifyDataSetChanged()方法來通知界面刷新。點擊查看更多介紹

5.中介者模式

  • 定義

用一箇中介對象來封裝一系列的對象交互。中介者使各對象不須要顯式地相互引用,從而使其耦合鬆散,並且能夠獨立地改變它們之間的交互。

  • 簡介

中介者模式的典型例子就是未加入 WTO 以前各個國家相互貿易,結構複雜,你們都加入WTO後是各個國家經過 WTO 來互相貿易,變得規範。點擊查看更多介紹

6.備忘錄模式

  • 定義

在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態。這樣之後就可將該對象恢復到保存的狀態。

  • 簡介

備忘錄模式的典型例子就是git版本管理工具,它幫咱們保存了每次提交後的項目狀態,在必要的時候咱們能夠回退到指定的版本中。點擊查看更多

7.解釋器模式

  • 定義

給定一個語言,定義它的文法的一種表示,並定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。

  • 簡介

解釋器的典型例子是在編譯原理中的應用,若是一種特定類型的問題發生的頻率足夠高,那麼可能就值得將該問題的各個實例表述爲一個簡單語言中的句子。這樣就能夠構建一個解釋器,該解釋器經過解釋這些句子來解決該問題。點擊查看更多

8.狀態模式

  • 定義

容許一個對象在其內部狀態改變時改變它的行爲。對象看起來彷佛修改了它的類。

  • 簡介

狀態模式主要解決對象的行爲依賴於它的狀態(屬性),而且能夠根據它的狀態改變而改變它的相關行爲。典型的例子是一我的在不一樣的狀態下完成一件事的結果多是不一樣的。點擊查看更多

9.策略模式

  • 定義

定義一系列的算法,把它們一個個封裝起來, 而且使它們可相互替換。本模式使得算法可獨立於使用它的客戶而變化。

  • 簡介

從策略模式的定義能夠看到它主要是將算法和客戶獨立開,一個典型的例子是排序算法,咱們給定一個數組,輸出排序後的結果,可是過程當中咱們能夠採起不一樣的排序算法,這些算法其實就是策略。點擊查看更多

10.責任鏈模式

  • 定義

使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它爲止。

  • 簡介

責任鏈模式,避免請求發送者與接收者耦合在一塊兒,讓多個對象都有可能接收請求,將這些對象鏈接成一條鏈,而且沿着這條鏈傳遞請求,直到有對象處理它爲止。點擊查看更多

11.訪問者模式

  • 定義

封裝一些做用於某種數據結構中的各元素的操做。它使你能夠在不改變各元素的類的前提下定義做用於這些元素的新操做。

  • 簡介

訪問者模式是一種將數據操做和數據結構分離的設計模式,它一般使用在對象結構比較穩定,可是常常須要在此對象結構上定義新的操做,或者須要對一個對象結構中的對象進行不少不一樣的而且不相關的操做,而須要避免讓這些操做"污染"這些對象的類,使用訪問者模式將這些封裝到類中。點擊查看更多

六.總結

到這裏,Java設計模式的學習總結就結束了,由於我的能力有限,有些模式只是簡單介紹了一下,想要進一步學習的話仍是要靠你們本身去查閱相關資料學習。熟練地掌握設計模式,還需多多的實踐.

相關文章
相關標籤/搜索