日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

java设计模式(1)

發布時間:2023/12/16 asp.net 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java设计模式(1) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1、設計模式概述

1.1 介紹

本教程來自http://c.biancheng.net/view/1317.html
目的是為了提高代碼的可重用性、代碼的可讀性和代碼的可靠性。
設計模式的本質是面向對象設計原則的實際運用,是對類的封裝性、繼承性和多態性以及類的關聯關系和組合關系的充分理解。正確使用設計模式具有以下優點:

  • 可以提高程序員的思維能力、編程能力和設計能力。
  • 使程序設計更加標準化、代碼編制更加工程化,使軟件開發效率大大提高,從而縮短軟件的開發周期。
  • 使設計的代碼可重用性高、可讀性強、可靠性高、靈活性好、可維護性強。

當然,軟件設計模式只是一個引導。在具體的軟件幵發中,必須根據設計的應用系統的特點和要求來恰當選擇。對于簡單的程序開發,可能寫一個簡單的算法要比引入某種設計模式更加容易。但對大項目的開發或者框架設計,用設計模式來組織代碼顯然更好。

1.2 分類

1.根據目的來分
根據模式是用來完成什么工作來劃分,這種方式可分為創建型模式、結構型模式和行為型模式 3 種。

  • 創建型模式:用于描述“怎樣創建對象”,它的主要特點是“將對象的創建與使用分離”。
    GoF 中提供了單例、原型、工廠方法、抽象工廠、建造者等 5 種創建型模式。
  • 結構型模式:用于描述如何將類或對象按某種布局組成更大的結構。
    GoF 中提供了代理、適配器、橋接、裝飾、外觀、享元、組合等 7 種結構型模式。
  • 行為型模式:用于描述類或對象之間怎樣相互協作共同完成單個對象都無法單獨完成的任務,以及怎樣分配職責。
    GoF 中提供了模板方法、策略、命令、職責鏈、狀態、觀察者、中介者、迭代器、訪問者、備忘錄、解釋器等 11 種行為型模式。

2.根據作用范圍來分
根據模式是主要用于類上還是主要用于對象上來分,這種方式可分為類模式和對象模式兩種。

  • 類模式:用于處理類與子類之間的關系,這些關系通過繼承來建立,是靜態的,在編譯時刻便確定下來了。
    GoF中的工廠方法、(類)適配器、模板方法、解釋器屬于該模式。
  • 對象模式:用于處理對象之間的關系,這些關系可以通過組合或聚合來實現,在運行時刻是可以變化的,更具動態性。
    GoF 中除了以上 4 種,其他的都是對象模式。

1.3 簡要介紹23種設計模式的功能

  • 單例(Singleton)模式:某個類只能生成一個實例,該類提供了一個全局訪問點供外部獲取該實例,其拓展是有限多例模式。
  • 原型(Prototype)模式:將一個對象作為原型,通過對其進行復制而克隆出多個和原型類似的新實例。
  • 工廠方法(Factory Method)模式:定義一個用于創建產品的接口,由子類決定生產什么產品。
  • 抽象工廠(AbstractFactory)模式:提供一個創建產品族的接口,其每個子類可以生產一系列相關的產品。
  • 建造者(Builder)模式:將一個復雜對象分解成多個相對簡單的部分,然后根據不同需要分別創建它們,最后構建成該復雜對象。
  • 代理(Proxy)模式:為某對象提供一種代理以控制對該對象的訪問。即客戶端通過代理間接地訪問該對象,從而限制、增強或修改該對象的一些特性。
  • 適配器(Adapter)模式:將一個類的接口轉換成客戶希望的另外一個接口,使得原本由于接口不兼容而不能一起工作的那些類能一起工作。
  • 橋接(Bridge)模式:將抽象與實現分離,使它們可以獨立變化。它是用組合關系代替繼承關系來實現,從而降低了抽象和實現這兩個可變維度的耦合度。
  • 裝飾(Decorator)模式:動態的給對象增加一些職責,即增加其額外的功能。
  • 外觀(Facade)模式:為多個復雜的子系統提供一個一致的接口,使這些子系統更加容易被訪問。
  • 享元(Flyweight)模式:運用共享技術來有效地支持大量細粒度對象的復用。
  • 組合(Composite)模式:將對象組合成樹狀層次結構,使用戶對單個對象和組合對象具有一致的訪問性。
  • 模板方法(TemplateMethod)模式:定義一個操作中的算法骨架,而將算法的一些步驟延遲到子類中,使得子類可以不改變該算法結構的情況下重定義該算法的某些特定步驟。
  • 策略(Strategy)模式:定義了一系列算法,并將每個算法封裝起來,使它們可以相互替換,且算法的改變不會影響使用算法的客戶。
  • 命令(Command)模式:將一個請求封裝為一個對象,使發出請求的責任和執行請求的責任分割開。
  • 職責鏈(Chain of Responsibility)模式:把請求從鏈中的一個對象傳到下一個對象,直到請求被響應為止。通過這種方式去除對象之間的耦合。
  • 狀態(State)模式:允許一個對象在其內部狀態發生改變時改變其行為能力。
  • 觀察者(Observer)模式:多個對象間存在一對多關系,當一個對象發生改變時,把這種改變通知給其他多個對象,從而影響其他對象的行為。
  • 中介者(Mediator)模式:定義一個中介對象來簡化原有對象之間的交互關系,降低系統中對象間的耦合度,使原有對象之間不必相互了解。
  • 迭代器(Iterator)模式:提供一種方法來順序訪問聚合對象中的一系列數據,而不暴露聚合對象的內部表示。
  • 訪問者(Visitor)模式:在不改變集合元素的前提下,為一個集合中的每個元素提供多種訪問方式,即每個元素有多個訪問者對象訪問。
  • 備忘錄(Memento)模式:在不破壞封裝性的前提下,獲取并保存一個對象的內部狀態,以便以后恢復它。
  • 解釋器(Interpreter)模式:提供如何定義語言的文法,以及對語言句子的解釋方法,即解釋器。
  • 2、UML

    UML(Unified Modeling Language,統一建模語言)是用來設計軟件藍圖的可視化建模語言,是一種為面向對象系統的產品進行說明、可視化和編制文檔的標準語言,獨立于任何一種具體的程序設計語言。

    2.1 基本構件

    在 UML 中,所有的描述由事物、關系和圖這些構件組成。下圖完整地描述了所有構件的關系:

    2.1.1 事物

    (1) 結構事物

    結構事物是模型中的靜態部分,用以呈現概念或實體的表現元素,如下表所示。

    (2)行為事物

    行為事物指 UML 模型中的動態部分,如下表所示。

    (3)分組事物

    目前只有一種分組事物,即包。包純碎是概念上的,只存在于開發階段,結構事物、行為事物甚至分組事物都有可能放在一個包中,如下表所示。

    (4)注釋事物

    注釋事物是解釋 UML 模型元素的部分,如下表所示。

    2.1.2 圖


    在 UML 2.0 的 13 種圖中,類圖(Class Diagrams)是使用頻率最高的 UML 圖之一。類圖描述系統中的類,以及各個類之間的關系的靜態視圖,能夠讓我們在正確編寫代碼之前對系統有一個全面的認識。類圖是一種模型類型,確切地說,是一種靜態模型類型。類圖表示類、接口和它們之間的協作關系,用于系統設計階段。

    類、接口、類圖



    類圖中,需注意以下幾點:

    • 抽象類或抽象方法用斜體表示
    • 如果是接口,則在類名上方加 <>
    • 字段和方法返回值的數據類型非必需
    • 靜態類或靜態方法加下劃線

    2.1.3 關系

    UML 將事物之間的聯系歸納為 6 種,并用對應的圖形類表示。下面根據類與類之間的耦合度從弱到強排列:
    依賴關系、關聯關系、聚合關系、組合關系、泛化關系和實現關系。其中泛化和實現的耦合度相等,它們是最強的。






    總結:

    案例:

    3、7種設計原則

    3.1 開閉原則

    定義

    軟件實體應當對擴展開放,對修改關閉(Software entities should be open for extension,but closed for modification),這就是開閉原則的經典定義。

    這里的軟件實體包括以下幾個部分:

  • 項目中劃分出的模塊
  • 類與接口
  • 方法
  • 開閉原則的含義是:當應用的需求改變時,在不修改軟件實體的源代碼或者二進制代碼的前提下,可以擴展模塊的功能,使其滿足新的需求。

    作用

    開閉原則是面向對象程序設計的終極目標,它使軟件實體擁有一定的適應性和靈活性的同時具備穩定性和延續性。具體來說,其作用如下。

  • 對軟件測試的影響
    軟件遵守開閉原則的話,軟件測試時只需要對擴展的代碼進行測試就可以了,因為原有的測試代碼仍然能夠正常運行。
  • 可以提高代碼的可復用性
    粒度越小,被復用的可能性就越大;在面向對象的程序設計中,根據原子和抽象編程可以提高代碼的可復用性。
  • 可以提高軟件的可維護性
    遵守開閉原則的軟件,其穩定性高和延續性強,從而易于擴展和維護。
  • 實現

    可以通過“抽象約束、封裝變化”來實現開閉原則,即通過接口或者抽象類為軟件實體定義一個相對穩定的抽象層,而將相同的可變因素封裝在相同的具體實現類中。

    因為抽象靈活性好,適應性廣,只要抽象的合理,可以基本保持軟件架構的穩定。而軟件中易變的細節可以從抽象派生來的實現類來進行擴展,當軟件需要發生變化時,只需要根據需求重新派生一個實現類來擴展就可以了。

    下面以 Windows 的桌面主題為例介紹開閉原則的應用。
    分析:Windows 的主題是桌面背景圖片、窗口顏色和聲音等元素的組合。用戶可以根據自己的喜愛更換自己的桌面主題,也可以從網上下載新的主題。這些主題有共同的特點,可以為其定義一個抽象類(Abstract Subject),而每個具體的主題(Specific Subject)是其子類。用戶窗體可以根據需要選擇或者增加新的主題,而不需要修改原代碼,所以它是滿足開閉原則的,其類圖如圖 1 所示。

    3.2 里氏替換

    定義

    繼承必須確保超類所擁有的性質在子類中仍然成立(Inheritance should ensure that any property proved about supertype objects also holds for subtype objects)。核心就是子類能完全替換它的基類。
    里氏替換原則是繼承與復用的基石,只有當子類可以替換掉基類,且系統的功能不受影響時,基類才能被復用,而子類也能夠在基礎類上增加新的行為。所以里氏替換原則指的是任何基類可以出現的地方,子類一定可以出現。
    里氏替換原則是對 “開閉原則” 的補充,實現 “開閉原則” 的關鍵步驟就是抽象化,而基類與子類的繼承關系就是抽象化的具體實現,所以里氏替換原則是對實現抽象化的具體步驟的規范。

    作用

    里氏替換原則的主要作用如下。

    • 里氏替換原則是實現開閉原則的重要方式之一。
    • 它克服了繼承中重寫父類造成的可復用性變差的缺點。
    • 它是動作正確性的保證。即類的擴展不會給已有的系統引入新的錯誤,降低了代碼出錯的可能性。
    • 加強程序的健壯性,同時變更時可以做到非常好的兼容性,提高程序的維護性、可擴展性,降低需求變更時引入的風險。

    實現

    里氏替換原則通俗來講就是:子類可以擴展父類的功能,但不能改變父類原有的功能。也就是說:子類繼承父類時,除添加新的方法完成新增功能外,盡量不要重寫父類的方法。

    根據上述理解,對里氏替換原則的定義可以總結如下:

    • 子類可以實現父類的抽象方法,但不能覆蓋父類的非抽象方法
    • 子類中可以增加自己特有的方法
    • 當子類的方法重載父類的方法時,方法的前置條件(即方法的輸入參數)要比父類的方法更寬松
    • 當子類的方法實現父類的方法時(重寫/重載或實現抽象方法),方法的后置條件(即方法的的輸出/返回值)要比父類的方法更嚴格或相等

    (上面第3條的解釋參見:https://blog.csdn.net/qq_39552268/article/details/112213037)

    通過重寫父類的方法來完成新的功能寫起來雖然簡單,但是整個繼承體系的可復用性會比較差,特別是運用多態比較頻繁時,程序運行出錯的概率會非常大。

    如果程序違背了里氏替換原則,則繼承類的對象在基類出現的地方會出現運行錯誤。這時其修正方法是:取消原來的繼承關系,重新設計它們之間的關系。

    關于里氏替換原則的例子,最有名的是“正方形不是長方形”。當然,生活中也有很多類似的例子,例如,企鵝、鴕鳥和幾維鳥從生物學的角度來劃分,它們屬于鳥類;但從類的繼承關系來看,由于它們不能繼承“鳥”會飛的功能,所以它們不能定義成“鳥”的子類。同樣,由于“氣球魚”不會游泳,所以不能定義成“魚”的子類;“玩具炮”炸不了敵人,所以不能定義成“炮”的子類等。

    下面以“幾維鳥不是鳥”為例來說明里氏替換原則。

    【例1】里氏替換原則在“幾維鳥不是鳥”實例中的應用。

    分析:鳥一般都會飛行,如燕子的飛行速度大概是每小時 120 千米。但是新西蘭的幾維鳥由于翅膀退化無法飛行。假如要設計一個實例,計算這兩種鳥飛行 300 千米要花費的時間。顯然,拿燕子來測試這段代碼,結果正確,能計算出所需要的時間;但拿幾維鳥來測試,結果會發生“除零異常”或是“無窮大”,明顯不符合預期,其類圖如圖 1 所示。

    public class LSPtest {public static void main(String[] args) {Bird bird1 = new Swallow();Bird bird2 = new BrownKiwi();bird1.setSpeed(120);bird2.setSpeed(120);System.out.println("如果飛行300公里:");try {System.out.println("燕子將飛行" + bird1.getFlyTime(300) + "小時.");System.out.println("幾維鳥將飛行" + bird2.getFlyTime(300) + "小時。");} catch (Exception err) {System.out.println("發生錯誤了!");}} } //鳥類 class Bird {double flySpeed;public void setSpeed(double speed) {flySpeed = speed;}public double getFlyTime(double distance) {return (distance / flySpeed);} } //燕子類 class Swallow extends Bird { } //幾維鳥類 class BrownKiwi extends Bird {public void setSpeed(double speed) {flySpeed = 0;} }

    運行結果:

    如果飛行300公里: 燕子將飛行2.5小時. 幾維鳥將飛行Infinity小時。

    程序運行錯誤的原因是:幾維鳥類重寫了鳥類的 setSpeed(double speed) 方法,這違背了里氏替換原則。正確的做法是:取消幾維鳥原來的繼承關系,定義鳥和幾維鳥的更一般的父類,如動物類,它們都有奔跑的能力。幾維鳥的飛行速度雖然為 0,但奔跑速度不為 0,可以計算出其奔跑 300 千米所要花費的時間。其類圖如圖 2 所示。

    3.3 依賴倒置

    定義

    高層模塊不應該依賴低層模塊,兩者都應該依賴其抽象;抽象不應該依賴細節,細節應該依賴抽象(High level modules shouldnot depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details. Details should depend upon abstractions)。其核心思想是:要面向接口編程,不要面向實現編程。

    由于在軟件設計中,細節具有多變性,而抽象層則相對穩定,因此以抽象為基礎搭建起來的架構要比以細節為基礎搭建起來的架構要穩定得多。這里的抽象指的是接口或者抽象類,而細節是指具體的實現類。

    使用接口或者抽象類的目的是制定好規范和契約,而不去涉及任何具體的操作,把展現細節的任務交給它們的實現類去完成。

    作用

    依賴倒置原則的主要作用如下。

    • 依賴倒置原則可以降低類間的耦合性。
    • 依賴倒置原則可以提高系統的穩定性。
    • 依賴倒置原則可以減少并行開發引起的風險。
    • 依賴倒置原則可以提高代碼的可讀性和可維護性。

    實現

    依賴倒置原則的目的是通過要面向接口的編程來降低類間的耦合性,所以我們在實際編程中只要遵循以下4點,就能在項目中滿足這個規則。

  • 每個類盡量提供接口或抽象類,或者兩者都具備。
  • 變量的聲明類型盡量是接口或者是抽象類。
  • 任何類都不應該從具體類派生。
  • 使用繼承時盡量遵循里氏替換原則。
  • 下面以“顧客購物程序”為例來說明依賴倒置原則的應用。

    【例1】依賴倒置原則在“顧客購物程序”中的應用。

    分析:本程序反映了 “顧客類”與“商店類”的關系。商店類中有 sell() 方法,顧客類通過該方法購物以下代碼定義了顧客類通過韶關網店 ShaoguanShop 購物:

    class Customer {public void shopping(ShaoguanShop shop) {//購物System.out.println(shop.sell());} }

    但是,這種設計存在缺點,如果該顧客想從另外一家商店(如婺源網店 WuyuanShop)購物,就要將該顧客的代碼修改如下:

    class Customer {public void shopping(WuyuanShop shop) {//購物System.out.println(shop.sell());} }

    顧客每更換一家商店,都要修改一次代碼,這明顯違背了開閉原則。存在以上缺點的原因是:顧客類設計時同具體的商店類綁定了,這違背了依賴倒置原則。解決方法是:定義“婺源網店”和“韶關網店”的共同接口 Shop,顧客類面向該接口編程,其代碼修改如下:

    class Customer {public void shopping(Shop shop) {//購物System.out.println(shop.sell());} }

    這樣,不管顧客類 Customer 訪問什么商店,或者增加新的商店,都不需要修改原有代碼了,其類圖如圖 1 所示。

    public class DIPtest {public static void main(String[] args) {Customer wang = new Customer();System.out.println("顧客購買以下商品:");wang.shopping(new ShaoguanShop());wang.shopping(new WuyuanShop());} } //商店 interface Shop {public String sell(); //賣 } //韶關網店 class ShaoguanShop implements Shop {public String sell() {return "韶關土特產:香菇、木耳……";} } //婺源網店 class WuyuanShop implements Shop {public String sell() {return "婺源土特產:綠茶、酒糟魚……";} } //顧客 class Customer {public void shopping(Shop shop) {//購物System.out.println(shop.sell());} }

    程序的運行結果如下:

    顧客購買以下商品: 韶關土特產:香菇、木耳…… 婺源土特產:綠茶、酒糟魚……

    3.4 單一職責

    定義

    又稱單一功能原則。這里的職責是指類變化的原因,單一職責原則規定一個類應該有且僅有一個引起它變化的原因,否則類應該被拆分(There should never be more than one reason for a class to change)。
    該原則提出對象不應該承擔太多職責,如果一個對象承擔了太多的職責,至少存在以下兩個缺點:

  • 一個職責的變化可能會削弱或者抑制這個類實現其他職責的能力;
  • 當客戶端需要該對象的某一個職責時,不得不將其他不需要的職責全都包含進來,從而造成冗余代碼或代碼的浪費。
  • 作用

    單一職責原則的核心就是控制類的粒度大小、將對象解耦、提高其內聚性。如果遵循單一職責原則將有以下優點。

    • 降低類的復雜度。一個類只負責一項職責,其邏輯肯定要比負責多項職責簡單得多。
    • 提高類的可讀性。復雜性降低,自然其可讀性會提高。
    • 提高系統的可維護性。可讀性提高,那自然更容易維護了。
    • 變更引起的風險降低。變更是必然的,如果單一職責原則遵守得好,當修改一個功能時,可以顯著降低對其他功能的影響。

    實現

    單一職責原則是最簡單但又最難運用的原則,需要設計人員發現類的不同職責并將其分離,再封裝到不同的類或模塊中。而發現類的多重職責需要設計人員具有較強的分析設計能力和相關重構經驗。
    下面以大學學生工作管理程序為例介紹單一職責原則的應用。
    分析:大學學生工作主要包括學生生活輔導和學生學業指導兩個方面的工作,其中生活輔導主要包括班委建設、出勤統計、心理輔導、費用催繳、班級管理等工作,學業指導主要包括專業引導、學習輔導、科研指導、學習總結等工作。如果將這些工作交給一位老師負責顯然不合理,正確的做法是生活輔導由輔導員負責,學業指導由學業導師負責,其類圖如圖所示。

    注意:單一職責同樣也適用于方法。一個方法應該盡可能做好一件事情。如果一個方法處理的事情太多,其顆粒度會變得很粗,不利于重用。

    3.5 接口隔離

    定義

    要求程序員盡量將臃腫龐大的接口拆分成更小的和更具體的接口,讓接口中只包含客戶感興趣的方法。客戶端不應該被迫依賴于它不使用的方法。該原則還有另外一個定義:一個類對另一個類的依賴應該建立在最小的接口上。
    以上兩個定義的含義是:要為各個類建立它們需要的專用接口,而不要試圖去建立一個很龐大的接口供所有依賴它的類去調用。
    接口隔離原則和單一職責都是為了提高類的內聚性、降低它們之間的耦合性,體現了封裝的思想,但兩者是不同的:

    • 單一職責原則注重的是職責,而接口隔離原則注重的是對接口依賴的隔離。
    • 單一職責原則主要是約束類,它針對的是程序中的實現和細節;接口隔離原則主要約束接口,主要針對抽象和程序整體框架的構建。

    作用

    接口隔離原則是為了約束接口、降低類對接口的依賴性,遵循接口隔離原則有以下 5 個優點。

  • 將臃腫龐大的接口分解為多個粒度小的接口,可以預防外來變更的擴散,提高系統的靈活性和可維護性。
  • 接口隔離提高了系統的內聚性,減少了對外交互,降低了系統的耦合性。
  • 如果接口的粒度大小定義合理,能夠保證系統的穩定性;但是,如果定義過小,則會造成接口數量過多,使設計復雜化;如果定義太大,靈活性降低,無法提供定制服務,給整體項目帶來無法預料的風險。
  • 使用多個專門的接口還能夠體現對象的層次,因為可以通過接口的繼承,實現對總接口的定義。
  • 能減少項目工程中的代碼冗余。過大的大接口里面通常放置許多不用的方法,當實現這個接口的時候,被迫設計冗余的代碼。
  • 實現

    在具體應用接口隔離原則時,應該根據以下幾個規則來衡量。

    • 接口盡量小,但是要有限度。一個接口只服務于一個子模塊或業務邏輯。
    • 為依賴接口的類定制服務。只提供調用者需要的方法,屏蔽不需要的方法。
    • 了解環境,拒絕盲從。每個項目或產品都有選定的環境因素,環境不同,接口拆分的標準就不同深入了解業務邏輯。
    • 提高內聚,減少對外交互。使接口用最少的方法去完成最多的事情。

    下面以學生成績管理程序為例介紹接口隔離原則的應用。
    分析:學生成績管理程序一般包含插入成績、刪除成績、修改成績、計算總分、計算均分、打印成績信息、査詢成績信息等功能,如果將這些功能全部放到一個接口中顯然不太合理,正確的做法是將它們分別放在輸入模塊、統計模塊和打印模塊等 3 個模塊中,其類圖如圖 1 所示。

    public class ISPtest {public static void main(String[] args) {InputModule input = StuScoreList.getInputModule();CountModule count = StuScoreList.getCountModule();PrintModule print = StuScoreList.getPrintModule();input.insert();count.countTotalScore();print.printStuInfo();//print.delete();} } //輸入模塊接口 interface InputModule {void insert();void delete();void modify(); } //統計模塊接口 interface CountModule {void countTotalScore();void countAverage(); } //打印模塊接口 interface PrintModule {void printStuInfo();void queryStuInfo(); } //實現類 class StuScoreList implements InputModule, CountModule, PrintModule {private StuScoreList() {}public static InputModule getInputModule() {return (InputModule) new StuScoreList();}public static CountModule getCountModule() {return (CountModule) new StuScoreList();}public static PrintModule getPrintModule() {return (PrintModule) new StuScoreList();}public void insert() {System.out.println("輸入模塊的insert()方法被調用!");}public void delete() {System.out.println("輸入模塊的delete()方法被調用!");}public void modify() {System.out.println("輸入模塊的modify()方法被調用!");}public void countTotalScore() {System.out.println("統計模塊的countTotalScore()方法被調用!");}public void countAverage() {System.out.println("統計模塊的countAverage()方法被調用!");}public void printStuInfo() {System.out.println("打印模塊的printStuInfo()方法被調用!");}public void queryStuInfo() {System.out.println("打印模塊的queryStuInfo()方法被調用!");} }

    運行結果:

    輸入模塊的insert()方法被調用! 統計模塊的countTotalScore()方法被調用! 打印模塊的printStuInfo()方法被調用!

    3.6 迪米特

    定義

    又叫作最少知識原則。迪米特法則的定義是:只與你的直接朋友交談,不跟“陌生人”說話。其含義是:如果兩個軟件實體無須直接通信,那么就不應當發生直接的相互調用,可以通過第三方轉發該調用。其目的是降低類之間的耦合度,提高模塊的相對獨立性。

    迪米特法則中的“朋友”是指:當前對象本身、當前對象的成員對象、當前對象所創建的對象、當前對象的方法參數等,這些對象同當前對象存在關聯、聚合或組合關系,可以直接訪問這些對象的方法。

    作用

    迪米特法則要求限制軟件實體之間通信的寬度和深度,正確使用迪米特法則將有以下兩個優點。

    • 降低了類之間的耦合度,提高了模塊的相對獨立性。
    • 由于親合度降低,從而提高了類的可復用率和系統的擴展性。

    但是,過度使用迪米特法則會使系統產生大量的中介類,從而增加系統的復雜性,使模塊之間的通信效率降低。所以,在釆用迪米特法則時需要反復權衡,確保高內聚和低耦合的同時,保證系統的結構清晰。

    實現

    從迪米特法則的定義和特點可知,它強調以下兩點:

    • 從依賴者的角度來說,只依賴應該依賴的對象。
    • 從被依賴者的角度說,只暴露應該暴露的方法。

    所以,在運用迪米特法則時要注意以下 6 點。

  • 在類的劃分上,應該創建弱耦合的類。類與類之間的耦合越弱,就越有利于實現可復用的目標。
  • 在類的結構設計上,盡量降低類成員的訪問權限。
  • 在類的設計上,優先考慮將一個類設置成不變類。
  • 在對其他類的引用上,將引用其他對象的次數降到最低。
  • 不暴露類的屬性成員,而應該提供相應的訪問器(set 和 get 方法)。
  • 謹慎使用序列化(Serializable)功能。
  • 【例1】明星與經紀人的關系實例。
    分析:明星由于全身心投入藝術,所以許多日常事務由經紀人負責處理,如與粉絲的見面會,與媒體公司的業務洽淡等。這里的經紀人是明星的朋友,而粉絲和媒體公司是陌生人,所以適合使用迪米特法則,其類圖如圖 1 所示。

    public class LoDtest {public static void main(String[] args) {Agent agent = new Agent();agent.setStar(new Star("林心如"));agent.setFans(new Fans("粉絲韓丞"));agent.setCompany(new Company("中國傳媒有限公司"));agent.meeting();agent.business();} } //經紀人 class Agent {private Star myStar;private Fans myFans;private Company myCompany;public void setStar(Star myStar) {this.myStar = myStar;}public void setFans(Fans myFans) {this.myFans = myFans;}public void setCompany(Company myCompany) {this.myCompany = myCompany;}public void meeting() {System.out.println(myFans.getName() + "與明星" + myStar.getName() + "見面了。");}public void business() {System.out.println(myCompany.getName() + "與明星" + myStar.getName() + "洽淡業務。");} } //明星 class Star {private String name;Star(String name) {this.name = name;}public String getName() {return name;} } //粉絲 class Fans {private String name;Fans(String name) {this.name = name;}public String getName() {return name;} } //媒體公司 class Company {private String name;Company(String name) {this.name = name;}public String getName() {return name;} }

    運行結果:

    粉絲韓丞與明星林心如見面了。 中國傳媒有限公司與明星林心如洽淡業務。

    3.7 合成復用

    定義

    又叫組合/聚合復用原則,它要求在軟件復用時,要盡量先使用組合或者聚合等關聯關系來實現,其次才考慮使用繼承關系來實現。

    如果要使用繼承關系,則必須嚴格遵循里氏替換原則。合成復用原則同里氏替換原則相輔相成的,兩者都是開閉原則的具體實現規范。

    作用

    通常類的復用分為繼承復用和合成復用兩種,繼承復用雖然有簡單和易實現的優點,但它也存在以下缺點。

  • 繼承復用破壞了類的封裝性。因為繼承會將父類的實現細節暴露給子類,父類對子類是透明的,所以這種復用又稱為“白箱”復用。
  • 子類與父類的耦合度高。父類的實現的任何改變都會導致子類的實現發生變化,這不利于類的擴展與維護。
  • 它限制了復用的靈活性。從父類繼承而來的實現是靜態的,在編譯時已經定義,所以在運行時不可能發生變化。
  • 采用組合或聚合復用時,可以將已有對象納入新對象中,使之成為新對象的一部分,新對象可以調用已有對象的功能,它有以下優點。

  • 它維持了類的封裝性。因為成分對象的內部細節是新對象看不見的,所以這種復用又稱為“黑箱”復用。
  • 新舊類之間的耦合度低。這種復用所需的依賴較少,新對象存取成分對象的唯一方法是通過成分對象的接口。
  • 復用的靈活性高。這種復用可以在運行時動態進行,新對象可以動態地引用與成分對象類型相同的對象。
  • 實現

    合成復用原則是通過將已有的對象納入新對象中,作為新對象的成員對象來實現的,新對象可以調用已有對象的功能,從而達到復用。

    下面以汽車分類管理程序為例來介紹合成復用原則的應用。

    分析:汽車按“動力源”劃分可分為汽油汽車、電動汽車等;按“顏色”劃分可分為白色汽車、黑色汽車和紅色汽車等。如果同時考慮這兩種分類,其組合就很多。圖 1 所示是用繼承關系實現的汽車分類的類圖。


    從上圖可以看出用繼承關系實現會產生很多子類,而且增加新的“動力源”或者增加新的“顏色”都要修改源代碼,這違背了開閉原則,顯然不可取。但如果改用組合關系實現就能很好地解決以上問題,其類圖如下圖所示。

    3.8 總結

    各種原則要求的側重點不同,下面我們分別用一句話歸納總結軟件設計模式的七大原則,如下表所示。

    實際上,這些原則的目的只有一個:降低對象之間的耦合,增加程序的可復用性、可擴展性和可維護性。

    記憶口訣:訪問加限制,函數要節儉,依賴不允許,動態加接口,父類要抽象,擴展不更改。

    在程序設計時,我們應該將程序功能最小化,每個類只干一件事。若有類似功能基礎之上添加新功能,則要合理使用繼承。對于多方法的調用,要會運用接口,同時合理設置接口功能與數量。最后類與類之間做到低耦合高內聚。

    4、23中設計模式介紹

    開始學習設計模式前,我們先來看看軟件架構的設計過程,及需要達成的目標和盡量避免的陷阱。

    代碼復用

    無論是開發哪種軟件產品,成本和時間都是最重要的。較少的開發時間意味著可以比競爭對手更早進入市場。較低的開發成本意味著能夠留出更多的營銷資金,覆蓋更廣泛的潛在客戶。

    其中,代碼復用是減少開發成本最常用的方式之一,其目的非常明顯,即:與其反復從頭開發,不如在新對象中重用已有的代碼。

    這個想法表面看起來很棒,但實際上要讓已有的代碼在全新的代碼中工作,還是需要付出額外努力的。組件間緊密的耦合、對具體類而非接口的依賴和硬編碼的行為都會降低代碼的靈活性,使得復用這些代碼變得更加困難。

    使用設計模式是增加軟件組件靈活性并使其易于復用的方式之一。但是,這可能也會讓組件變得更加復雜。

    一般情況下,復用可以分為三個層次。在最底層,可以復用類、類庫、容器,也許還有一些類的“團體(例如容器和迭代器)”。

    框架位于最高層。它們能幫助你精簡自己的設計,可以明確解決問題所需的抽象概念,然后用類來表示這些概念并定義其關系。例如,JUnit 是一個小型框架,也是框架的“Hello, world”,其中定義了 Test、TestCase 和 TestSuite 這幾個類及其關系。框架通常比單個類的顆粒度要大。你可以通過在某處構建子類來與框架建立聯系。這些子類信奉“別給我們打電話,我們會給你打電話的。”

    還有一個中間層次。這是我覺得設計模式所處的位置。設計模式比框架更小且更抽象。它們實際上是對一組類的關系及其互動方式的描述。當你從類轉向模式,并最終到達框架的過程中,復用程度會不斷增加。

    中間層次的優點在于模式提供的復用方式要比框架的風險小。創建框架是一項投入重大且風險很高的工作,模式則能讓你獨立于具體代碼來復用設計思想和理念。

    擴展性

    需求變化是程序員生命中唯一不變的事情。比如以下幾種場景:

    • 你在 Windows 平臺上發布了一款游戲,現在人們想要 Mac OS 的版本。
    • 你創建了一個使用方形按鈕的 GUI 框架,但幾個月后開始流行原型按鈕。
    • 你設計了一款優秀的電子商務網站,但僅僅幾個月后,客戶就要求新增電話訂單的功能。

    每個軟件開發者都經歷過許多相似的故事,導致它們發生的原因也不少。

    首先,在完成了第一版的程序后,我們就應該做好了從頭開始優化重寫代碼的準備,因為現在你已經能在很多方面更好的理解問題了,同時在專業水平上也有所提高,所以之前的代碼現在看上去可能會顯得很糟糕。

    其次,可能是在你掌控之外的某些事情發生了變化,這也是導致許多開發團隊轉變最初想法的原因。比如,每位在網絡應用中使用 Flash 的開發者都必須重新開發或移植代碼,因為不斷地有瀏覽器停止對 Flash 格式地支持。

    最后,可能是需求的改變,之前你的客戶對當前版本的程序感到滿意,但是現在希望對程序進行 11 個“小小”的改動,使其可完成原始計劃階段中完全沒有提到的功能,新增或改變功能。

    當然這也有好的一面,如果有人要求你對程序進行修改,至少說明還有人關心它。因此在設計程序架構時,有經驗的開發者都會盡量選擇支持未來任何可能變更的方式。

    如何正確使用設計模式?

    設計模式不是為每個人準備的,而是基于業務來選擇設計模式,需要時就能想到它。要明白一點,技術永遠為業務服務,技術只是滿足業務需要的一個工具。我們需要掌握每種設計模式的應用場景、特征、優缺點,以及每種設計模式的關聯關系,這樣就能夠很好地滿足日常業務的需要。

    許多設計模式的功能類似,界限不是特別清楚(為了能讓大家更好的理解,每個章節后面都列出了類似功能設計模式之間的對比)。大家不要疑惑,設計模式不是為了特定場景而生的,而是為了讓大家可以更好和更快地開發。

    設計模式只是實現了七大設計原則的具體方式,套用太多設計模式只會陷入模式套路陷阱,最后代碼寫的凌亂不堪。

    在實際工作中很少會規定必須使用哪種設計模式,這樣只會限制別人。不能為了使用設計模式而去做架構,而是有了做架構的需求后,發現它符合某一類設計模式的結構,在將兩者結合。

    設計模式要活學活用,不要生搬硬套。想要游刃有余地使用設計模式,需要打下牢固的程序設計語言基礎、夯實自己的編程思想、積累大量的時間經驗、提高開發能力。目的都是讓程序低耦合,高復用,高內聚,易擴展,易維護。

  • 需求驅動
    不僅僅是功能性需求,需求驅動還包括性能和運行時的需求,如軟件的可維護性和可復用性等方面。設計模式是針對軟件設計的,而軟件設計是針對需求的,一定不要為了使用設計模式而使用設計模式,否則可能會使設計變得復雜,使軟件難以調試和維護。
  • 分析成功的模式應用項目
    對現有的應用實例進行分析是一個很好的學習途徑,應當注意學習已有的項目,而不僅是學習設計模式如何實現,更重要的是注意在什么場合使用設計模式。
  • 充分了解所使用的開發平臺
    設計模式大部分都是針對面向對象的軟件設計,因此在理論上適合任何面向對象的語言,但隨著技術的發展和編程環境的改善,設計模式的實現方式會有很大的差別。在一些平臺下,某些設計模式是自然實現的。
  • 不僅指編程語言,平臺還包括平臺引入的技術。例如,Java EE 引入了反射機制和依賴注入,這些技術的使用使設計模式的實現方式產生了改變。
    4. 在編程中領悟模式
    軟件開發是一項實踐工作,最直接的方法就是編程。沒有從來不下棋卻熟悉定式的圍棋高手,也沒有不會編程就能成為架構設計師的先例。掌握設計模式是水到渠成的事情,除了理論只是和實踐積累,可能會“漸悟”或者“頓悟”。
    5.避免設計過度
    設計模式解決的是設計不足的問題,但同時也要避免設計過度。一定要牢記簡潔原則,要知道設計模式是為了使設計簡單,而不是更復雜。如果引入設計模式使得設計變得復雜,只能說我們把簡單問題復雜化了,問題本身不需要設計模式。

    這里需要把握的是需求變化的程度,一定要區分需求的穩定部分和可變部分。一個軟件必然有穩定部分,這個部分就是核心業務邏輯。如果核心業務邏輯發生變化,軟件就沒有存在的必要,核心業務邏輯是我們需要固化的。對于可變的部分,需要判斷可能發生變化的程度來確定設計策略和設計風險。要知道,設計過度與設計不足同樣對項目有害。
    學習設計模式,死記硬背是沒用的,還要從實踐中理解,本教程后面會結合實例和源碼來講解如何使用設計模式。

    需要特別聲明的是,在日常應用中,設計模式從來都不是單個設計模式獨立使用的。在實際應用中,通常多個設計模式混合使用,你中有我,我中有你。下圖完整地描述了設計模式之間的混用關系,希望對大家有所幫助。

    創建型模式

    創建型模式的主要關注點是“怎樣創建對象?”,它的主要特點是“將對象的創建與使用分離”。這樣可以降低系統的耦合度,使用者不需要關注對象的創建細節,對象的創建由相關的工廠來完成。就像我們去商場購買商品時,不需要知道商品是怎么生產出來一樣,因為它們由專門的廠商生產。

    創建型模式分為以下幾種。

    • 單例(Singleton)模式:某個類只能生成一個實例,該類提供了一個全局訪問點供外部獲取該實例,其拓展是有限多例模式。
    • 原型(Prototype)模式:將一個對象作為原型,通過對其進行復制而克隆出多個和原型類似的新實例。
    • 工廠方法(FactoryMethod)模式:定義一個用于創建產品的接口,由子類決定生產什么產品。
    • 抽象工廠(AbstractFactory)模式:提供一個創建產品族的接口,其每個子類可以生產一系列相關的產品。
    • 建造者(Builder)模式:將一個復雜對象分解成多個相對簡單的部分,然后根據不同需要分別創建它們,最后構建成該復雜對象。

    4.1 單例模式

    定義特點

    指一個類只有一個實例,且該類能自行創建這個實例的一種模式。

    單例模式有 3 個特點:

    • 單例類只有一個實例對象;
    • 該單例對象必須由單例類自行創建;
    • 單例類對外提供一個訪問該單例的全局訪問點。

    優缺點

    單例模式的優點:

    • 單例模式可以保證內存里只有一個實例,減少了內存的開銷。
    • 可以避免對資源的多重占用。
    • 單例模式設置全局訪問點,可以優化和共享資源的訪問。

    單例模式的缺點:

    • 單例模式一般沒有接口,擴展困難。如果要擴展,則除了修改原來的代碼,沒有第二種途徑,違背開閉原則。
    • 在并發測試中,單例模式不利于代碼調試。在調試過程中,如果單例中的代碼沒有執行完,也不能模擬生成一個新的對象。
    • 單例模式的功能代碼通常寫在一個類中,如果功能設計不合理,則很容易違背單一職責原則。

    使用場景

    例如,Windows 中只能打開一個任務管理器,這樣可以避免因打開多個任務管理器窗口而造成內存資源的浪費,或出現各個窗口顯示內容的不一致等錯誤。

    在計算機系統中,還有 Windows 的回收站、操作系統中的文件系統、多線程中的線程池、顯卡的驅動程序對象、打印機的后臺處理服務、應用程序的日志對象、數據庫的連接池、網站的計數器、Web 應用的配置對象、應用程序中的對話框、系統中的緩存等常常被設計成單例。

    單例模式在現實生活中的應用也非常廣泛,例如公司 CEO、部門經理等都屬于單例模型。J2EE 標準中的 ServletContext 和 ServletContextConfig、Spring 框架應用中的 ApplicationContext、數據庫中的連接池等也都是單例模式。

    對于 Java 來說,單例模式可以保證在一個 JVM 中只存在單一實例。單例模式的應用場景主要有以下幾個方面。

    • 需要頻繁創建的一些類,使用單例可以降低系統的內存壓力,減少 GC。
    • 某類只要求生成一個對象的時候,如一個班中的班長、每個人的身份證號等。
    • 某些類創建實例時占用資源較多,或實例化耗時較長,且經常使用。
    • 某類需要頻繁實例化,而創建的對象又頻繁被銷毀的時候,如多線程的線程池、網絡連接池等。
    • 頻繁訪問數據庫或文件的對象。
    • 對于一些控制硬件級別的操作,或者從系統上來講應當是單一控制邏輯的操作,如果有多個實例,則系統會完全亂套。
    • 當對象需要被共享的場合。由于單例模式只允許創建一個對象,共享該對象可以節省內存,并加快對象訪問速度。如 Web 中的配置對象、數據庫的連接池等。

    實現

    單例模式是設計模式中最簡單的模式之一。通常,普通類的構造函數是公有的,外部類可以通過“new 構造函數()”來生成多個實例。但是,如果將類的構造函數設為私有的,外部類就無法調用該構造函數,也就無法生成多個實例。這時該類自身必須定義一個靜態私有實例,并向外提供一個靜態的公有函數用于創建或獲取該靜態私有實例。

    第 1 種:懶漢式單例(雙重檢查保證效率)

    該模式的特點是類加載時沒有生成單例,只有當第一次調用 getlnstance 方法時才去創建這個單例。

    class Singleton {private Singleton() {}private static volatile Singleton instance;public static Singleton getInstance() {if (instance==null){synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;} }

    如果編寫的是多線程程序,則不要刪除上例代碼中的關鍵字 volatile 和 synchronized,否則將存在線程非安全的問題。

    第 2 種:餓漢式單例

    該模式的特點是類一旦加載就創建一個單例,保證在調用 getInstance 方法之前單例已經存在了。

    public class HungrySingleton {private static final HungrySingleton instance = new HungrySingleton();private HungrySingleton() {}public static HungrySingleton getInstance() {return instance;} }

    餓漢式單例在類創建的同時就已經創建好一個靜態的對象供系統使用,以后不再改變,所以是線程安全的,可以直接用于多線程而不會出現問題。

    單例模式的擴展

    單例模式可擴展為有限的多例(Multitcm)模式,這種模式可生成有限個實例并保存在 ArrayList 中,客戶需要時可隨機獲取。

    4.2 原型模式

    定義特點

    原型(Prototype)模式的定義如下:用一個已經創建的實例作為原型,通過復制該原型對象來創建一個和原型相同或相似的新對象。在這里,原型實例指定了要創建的對象的種類。用這種方式創建對象非常高效,根本無須知道對象創建的細節。

    優缺點

    原型模式的優點:

    • Java 自帶的原型模式基于內存二進制流的復制,在性能上比直接 new 一個對象更加優良。
    • 可以使用深克隆方式保存對象的狀態,使用原型模式將對象復制一份,并將其狀態保存起來,簡化了創建對象的過程,以便在需要的時候使用(例如恢復到歷史某一狀態),可輔助實現撤銷操作。

    原型模式的缺點:

    • 需要為每一個類都配置一個 clone 方法
    • clone 方法位于類的內部,當對已有類進行改造的時候,需要修改代碼,違背了開閉原則。
    • 當實現深克隆時,需要編寫較為復雜的代碼,而且當對象之間存在多重嵌套引用時,為了實現深克隆,每一層對象對應的類都必須支持深克隆,實現起來會比較麻煩。因此,深克隆、淺克隆需要運用得當。

    使用場景

    例如,Windows 操作系統的安裝通常較耗時,如果復制就快了很多。在生活中復制的例子非常多,這里不一一列舉了。

    原型模式通常適用于以下場景。

    • 對象之間相同或相似,即只是個別的幾個屬性不同的時候。
    • 創建對象成本較大,例如初始化時間長,占用CPU太多,或者占用網絡資源太多等,需要優化資源。
    • 創建一個對象需要繁瑣的數據準備或訪問權限等,需要提高性能或者提高安全性。
    • 系統中大量使用該類對象,且各個調用者都需要給它的屬性重新賦值。

    在 Spring 中,原型模式應用的非常廣泛,例如 scope=‘prototype’、JSON.parseObject() 等都是原型模式的具體應用。

    實現

    原型模式的克隆分為淺克隆和深克隆。

    • 淺克隆:創建一個新對象,新對象的屬性和原來對象完全相同,對于非基本類型屬性,仍指向原有屬性所指向的對象的內存地址。
    • 深克隆:創建一個新對象,屬性中引用的其他對象也會被克隆,不再指向原有對象地址。

    注:String類型通過常量賦值時相當于基本數據類型,通過new關鍵字創建對象時便是引用數據類型。

    String str1 = new String("ABC"); String str2 = new String("ABC"); System.out.println(str1 == str2); //falseString str3 = "ABC"; String str4 = "ABC"; String str5 = "AB" + "C"; System.out.println(str3 == str4); //true System.out.println(str3 == str5); // trueString a = "ABC"; String b = "AB"; String c = b + "C"; System.out.println( a == c );//false

    注意最后一個a與c相等的判斷:a、b在編譯時就已經被確定了,而c是引用變量,不會在編譯時就被確定。運行時b與“C”的拼接是通過StringBuilder(JDK1.5之前是StringBuffer)實現的,最后調用的StringBuilder的toString函數返回一個新的String對象。

    淺克隆

    Java 中的 Object 類提供了淺克隆的 clone() 方法,具體原型類只要實現 Cloneable 接口就可實現對象的淺克隆,這里的 Cloneable 接口就是抽象原型類。其代碼如下:

    //具體原型類 class Realizetype implements Cloneable {public String name="coder";Realizetype() {System.out.println("具體原型創建成功!");}public Object clone() throws CloneNotSupportedException {System.out.println("具體原型復制成功!");return super.clone();} } //原型模式的測試類 public class PrototypeTest {public static void main(String[] args) throws CloneNotSupportedException {Realizetype obj1 = new Realizetype();Realizetype obj2 = (Realizetype) obj1.clone();System.out.println("obj1==obj2?" + (obj1 == obj2));System.out.println("clone1.name==realizetype1.name?"+(clone1.name==realizetype1.name));} }

    運行結果:

    具體原型創建成功! 具體原型復制成功! obj1==obj2?false

    深克隆

    兩種實現方式:重寫clone、通過對象序列化

    方法一:重寫clone

    與通過重寫clone方法實現淺拷貝的基本思路一樣,只需要為對象圖的每一層的每一個對象都實現Cloneable接口并重寫clone方法,最后在最頂層的類的重寫的clone方法中調用所有的clone方法即可實現深拷貝。簡單的說就是:每一層的每個對象都進行淺拷貝=深拷貝。

    public class DeepCopy {public static void main(String[] args) {Student s1 = new Student("s1", new Age(20), 175);Student clone = (Student) s1.clone();System.out.println(clone.getAge()==s1.getAge());System.out.println();} }class Age implements Cloneable {private int age;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Age(int age) {this.age = age;}@Overridepublic String toString() {return "Age{" +"age=" + age +'}';}@Overrideprotected Object clone() {Object object = null;try {object = super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return object;} }class Student implements Cloneable {private String name;private Age age;private int length;public String getName() {return name;}public void setName(String name) {this.name = name;}public Age getAge() {return age;}public void setAge(Age age) {this.age = age;}public int getLength() {return length;}public void setLength(int length) {this.length = length;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", length=" + length +'}';}public Student(String name, Age age, int length) {this.name = name;this.age = age;this.length = length;}@Overrideprotected Object clone() {Object object = null;try {object = super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}Student student = (Student) object;student.age = (Age) student.getAge().clone();return object;} }

    方法二:通過對象序列化

    雖然層次調用clone方法可以實現深拷貝,但是顯然代碼量實在太大。特別對于屬性數量比較多、層次比較深的類而言,每個類都要重寫clone方法太過繁瑣。

    將對象序列化為字節序列后,默認會將該對象的整個對象圖進行序列化,再通過反序列即可完美地實現深拷貝。

    import java.io.*;public class DeepCopy {public static void main(String[] args) throws IOException, ClassNotFoundException {Age age = new Age(20);Student s1 = new Student("s1", age, 180);ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(s1);oos.flush();ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bis);Student clone = (Student) ois.readObject();ois.close();bis.close();oos.close();bos.close();System.out.println(clone == s1);System.out.println();} }class Age implements Serializable {private int age;public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Age(int age) {this.age = age;}@Overridepublic String toString() {return "Age{" +"age=" + age +'}';}}class Student implements Serializable {private String name;private Age age;private int length;public String getName() {return name;}public void setName(String name) {this.name = name;}public Age getAge() {return age;}public void setAge(Age age) {this.age = age;}public int getLength() {return length;}public void setLength(int length) {this.length = length;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", length=" + length +'}';}public Student(String name, Age age, int length) {this.name = name;this.age = age;this.length = length;} }

    原型模式的擴展

    原型模式可擴展為帶原型管理器的原型模式,它在原型模式的基礎上增加了一個原型管理器 PrototypeManager 類。該類用 HashMap 保存多個復制的原型,Client 類可以通過管理器的 get(String id) 方法從中獲取復制的原型。

    工廠模式

    在日常開發中,凡是需要生成復雜對象的地方,都可以嘗試考慮使用工廠模式來代替。

    注意:上述復雜對象指的是類的構造函數參數過多等對類的構造有影響的情況,因為類的構造過于復雜,如果直接在其他業務類內使用,則兩者的耦合過重,后續業務更改,就需要在任何引用該類的源代碼內進行更改,光是查找所有依賴就很消耗時間了,更別說要一個一個修改了。

    工廠模式的定義:定義一個創建產品對象的工廠接口,將產品對象的實際創建工作推遲到具體子工廠類當中。這滿足創建型模式中所要求的“創建與使用相分離”的特點。

    按實際業務場景劃分,工廠模式有 3 種不同的實現方式,分別是簡單工廠模式、工廠方法模式和抽象工廠模式。

    我們把被創建的對象稱為“產品”,把創建產品的對象稱為“工廠”。如果要創建的產品不多,只要一個工廠類就可以完成,這種模式叫“簡單工廠模式”。

    在簡單工廠模式中創建實例的方法通常為靜態(static)方法,因此簡單工廠模式(Simple Factory Pattern)又叫作靜態工廠方法模式(Static Factory Method Pattern)。

    簡單來說,簡單工廠模式有一個具體的工廠類,可以生成多個不同的產品,屬于創建型設計模式。

    簡單工廠模式每增加一個產品就要增加一個具體產品類和一個對應的具體工廠類,這增加了系統的復雜度,違背了“開閉原則”。

    “工廠方法模式”是對簡單工廠模式的進一步抽象化,其好處是可以使系統在不修改原來代碼的情況下引進新的產品,即滿足開閉原則。

    4.3 簡單工廠模式

    定義特點

    我們把被創建的對象稱為“產品”,把創建產品的對象稱為“工廠”。如果要創建的產品不多,只要一個工廠類就可以完成,這種模式叫“簡單工廠模式”。

    在簡單工廠模式中創建實例的方法通常為靜態(static)方法,因此簡單工廠模式(Simple Factory Pattern)又叫作靜態工廠方法模式(Static Factory Method Pattern)。

    優缺點

    優點:
    1- 工廠類包含必要的邏輯判斷,可以決定在什么時候創建哪一個產品的實例。客戶端可以免除直接創建產品對象的職責,很方便的創建出相應的產品。工廠和產品的職責區分明確。

    • 客戶端無需知道所創建具體產品的類名,只需知道參數即可。
    • 也可以引入配置文件,在不修改客戶端代碼的情況下更換和添加新的具體產品類。

    缺點:

    • 簡單工廠模式的工廠類單一,負責所有產品的創建,職責過重,一旦異常,整個系統將受影響。且工廠類代碼會非常臃腫,違背高聚合原則。
    • 使用簡單工廠模式會增加系統中類的個數(引入新的工廠類),增加系統的復雜度和理解難度
    • 系統擴展困難,一旦增加新產品不得不修改工廠邏輯,在產品類型較多時,可能造成邏輯過于復雜
    • 簡單工廠模式使用了 static 工廠方法,造成工廠角色無法形成基于繼承的等級結構。

    使用場景

    對于產品種類相對較少的情況,考慮使用簡單工廠模式。使用簡單工廠模式的客戶端只需要傳入工廠類的參數,不需要關心如何創建對象的邏輯,可以很方便地創建所需產品。

    實現

    簡單工廠模式的主要角色如下:

    • 簡單工廠(SimpleFactory):是簡單工廠模式的核心,負責實現創建所有實例的內部邏輯。工廠類的創建產品類的方法可以被外界直接調用,創建所需的產品對象。
    • 抽象產品(Product):是簡單工廠創建的所有對象的父類,負責描述所有實例共有的公共接口。
    • 具體產品(ConcreteProduct):是簡單工廠模式的創建目標。

    其結構圖如下圖所示。

    public class Client {public static void main(String[] args) {SimpleFactory sf = new SimpleFactory();Product productA = sf.makeProduct(0);Product productB = sf.makeProduct(1);productA.show();productB.show();}//抽象產品public interface Product {void show();}//具體產品:ProductAstatic class ConcreteProduct1 implements Product {public void show() {System.out.println("具體產品1顯示...");}}//具體產品:ProductBstatic class ConcreteProduct2 implements Product {public void show() {System.out.println("具體產品2顯示...");}}final class Const {static final int PRODUCT_A = 0;static final int PRODUCT_B = 1;static final int PRODUCT_C = 2;}static class SimpleFactory {public static Product makeProduct(int kind) {switch (kind) {case Const.PRODUCT_A:return new ConcreteProduct1();case Const.PRODUCT_B:return new ConcreteProduct2();}return null;}} }

    4.4 工廠方法模式

    定義特點

    在《簡單工廠模式》一節我們介紹了簡單工廠模式,提到了簡單工廠模式違背了開閉原則,而“工廠方法模式”是對簡單工廠模式的進一步抽象化,其好處是可以使系統在不修改原來代碼的情況下引進新的產品,即滿足開閉原則。

    優缺點

    優點:

    • 用戶只需要知道具體工廠的名稱就可得到所要的產品,無須知道產品的具體創建過程。
    • 靈活性增強,對于新產品的創建,只需多寫一個相應的工廠類。
    • 典型的解耦框架。高層模塊只需要知道產品的抽象類,無須關心其他實現類,滿足迪米特法則、依賴倒置原則和里氏替換原則。

    缺點:

    • 類的個數容易過多,增加復雜度
    • 增加了系統的抽象性和理解難度
    • 抽象產品只能生產一種產品,此弊端可使用抽象工廠模式解決。

    使用場景

    • 客戶只知道創建產品的工廠名,而不知道具體的產品名。如 TCL 電視工廠、海信電視工廠等。
    • 創建對象的任務由多個具體子工廠中的某一個完成,而抽象工廠只提供創建產品的接口。
    • 客戶不關心創建產品的細節,只關心產品的品牌

    實現

    工廠方法模式由抽象工廠、具體工廠、抽象產品和具體產品等4個要素構成。
    工廠方法模式的主要角色如下。

  • 抽象工廠(Abstract Factory):提供了創建產品的接口,調用者通過它訪問具體工廠的工廠方法 newProduct() 來創建產品。
  • 具體工廠(ConcreteFactory):主要是實現抽象工廠中的抽象方法,完成具體產品的創建。
  • 抽象產品(Product):定義了產品的規范,描述了產品的主要特性和功能。
  • 具體產品(ConcreteProduct):實現了抽象產品角色所定義的接口,由具體工廠來創建,它同具體工廠之間一一對應。
  • 其結構圖如圖 1 所示。

    package com.atguigu;/*** @PackageName: com.atguigu* @ClassName: AbstractFactoryTest* @Author: user-lihao* @Date: 2021/10/12 20:40* @Description:**/ public class AbstractFactoryTest {public static Product getProduct(AbstractFactory af){Product p=af.newProduct();return p;}public static void main(String[] args) {Product product1 = getProduct(new ConcreteFactory1());product1.show();//具體產品1顯示...} } //抽象產品:提供了產品的接口 interface Product {public void show(); } //具體產品1:實現抽象產品中的抽象方法 class ConcreteProduct1 implements Product {public void show() {System.out.println("具體產品1顯示...");} } //具體產品2:實現抽象產品中的抽象方法 class ConcreteProduct2 implements Product {public void show() {System.out.println("具體產品2顯示...");} } //抽象工廠:提供了產品的生成方法 interface AbstractFactory {public Product newProduct(); } //具體工廠1:實現了產品的生成方法 class ConcreteFactory1 implements AbstractFactory {public Product newProduct() {System.out.println("具體工廠1生成-->具體產品1...");return new ConcreteProduct1();} } //具體工廠2:實現了產品的生成方法 class ConcreteFactory2 implements AbstractFactory {public Product newProduct() {System.out.println("具體工廠2生成-->具體產品2...");return new ConcreteProduct2();} }

    4.5 抽象工廠模式

    同種類稱為同等級,也就是說:工廠方法模式只考慮生產同等級的產品,但是在現實生活中許多工廠是綜合型的工廠,能生產多等級(種類) 的產品,如農場里既養動物又種植物,電器廠既生產電視機又生產洗衣機或空調,大學既有軟件專業又有生物專業等。

    本節要介紹的抽象工廠模式將考慮多等級產品的生產,將同一個具體工廠所生產的位于不同等級的一組產品稱為一個產品族,下圖所示的是海爾工廠和 TCL 工廠所生產的電視機與空調對應的關系圖。

    定義特點

    抽象工廠(AbstractFactory)模式的定義:是一種為訪問類提供一個創建一組相關或相互依賴對象的接口,且訪問類無須指定所要產品的具體類就能得到同族的不同等級的產品的模式結構。

    抽象工廠模式是工廠方法模式的升級版本,工廠方法模式只生產一個等級的產品,而抽象工廠模式可生產多個等級的產品。

    優缺點

    抽象工廠模式除了具有工廠方法模式的優點外,其他主要優點如下。

    • 可以在類的內部對產品族中相關聯的多等級產品共同管理,而不必專門引入多個新的類來進行管理。
    • 當需要產品族時,抽象工廠可以保證客戶端始終只使用同一個產品的產品組。
    • 抽象工廠增強了程序的可擴展性,當增加一個新的產品族時,不需要修改原代碼,滿足開閉原則。

    其缺點是:當產品族中需要增加一個新的產品時,所有的工廠類都需要進行修改。增加了系統的抽象性和理解難度。

    使用場景

    使用抽象工廠模式一般要滿足以下條件:

    • 系統中有多個產品族,每個具體工廠創建同一族但屬于不同等級結構的產品。
    • 系統一次只可能消費其中某一族產品,即同族的產品一起使用。

    抽象工廠模式最早的應用是用于創建屬于不同操作系統的視窗構件。如 Java 的 AWT 中的 Button 和 Text 等構件在 Windows 和 UNIX 中的本地實現是不同的。

    抽象工廠模式通常適用于以下場景:

    • 當需要創建的對象是一系列相互關聯或相互依賴的產品族時,如電器工廠中的電視機、洗衣機、空調等。
    • 系統中有多個產品族,但每次只使用其中的某一族產品。如有人只喜歡穿某一個品牌的衣服和鞋。
    • 系統中提供了產品的類庫,且所有產品的接口相同,客戶端不依賴產品實例的創建細節和內部結構。

    實現

    抽象工廠模式的主要角色如下。

  • 抽象工廠(Abstract Factory):提供了創建產品的接口,它包含多個創建產品的方法 newProduct(),可以創建多個不同等級的產品。
  • 具體工廠(Concrete Factory):主要是實現抽象工廠中的多個抽象方法,完成具體產品的創建。
  • 抽象產品(Product):定義了產品的規范,描述了產品的主要特性和功能,抽象工廠模式有多個抽象產品。
  • 具體產品(ConcreteProduct):實現了抽象產品角色所定義的接口,由具體工廠來創建,它同具體工廠之間是多對一的關系。
  • 抽象工廠結構如下:

    public class AbstractFactoryTest {public static Product1 getProduct1(AbstractFactory af) {return af.newProduct1();}public static Product2 getProduct2(AbstractFactory af) {return af.newProduct2();}public static void main(String[] args) {Product1 p2 = getProduct1(new ConcreteFactory2());p2.show();//product21-show()Product2 p1 = getProduct2(new ConcreteFactory1());p1.show();//product12-show()} }interface AbstractFactory {public Product1 newProduct1();public Product2 newProduct2(); }class ConcreteFactory1 implements AbstractFactory {@Overridepublic Product1 newProduct1() {return new Product11();}@Overridepublic Product2 newProduct2() {return new Product12();} }class ConcreteFactory2 implements AbstractFactory {@Overridepublic Product1 newProduct1() {return new Product21();}@Overridepublic Product2 newProduct2() {return new Product22();} }interface Product1 {public void show(); }interface Product2 {public void show(); }class Product11 implements Product1 {@Overridepublic void show() {System.out.println("product11-show()");} }class Product12 implements Product2 {@Overridepublic void show() {System.out.println("product12-show()");} }class Product21 implements Product1 {@Overridepublic void show() {System.out.println("product21-show()");} }class Product22 implements Product2 {@Overridepublic void show() {System.out.println("product22-show()");} }

    擴展

    抽象工廠模式的擴展有一定的“開閉原則”傾斜性:

    • 當增加一個新的產品族時只需增加一個新的具體工廠,不需要修改原代碼,滿足開閉原則。
    • 當產品族中需要增加一個新種類的產品時,則所有的工廠類都需要進行修改,不滿足開閉原則。

    另一方面,當系統中只存在一個等級結構的產品時,抽象工廠模式將退化到工廠方法模式。

    4.6 建造者模式

    定義特點

    建造者(Builder)模式的定義:指將一個復雜對象的構造與它的表示分離,使同樣的構建過程可以創建不同的表示,這樣的設計模式被稱為建造者模式。它是將一個復雜的對象分解為多個簡單的對象,然后一步一步構建而成。它將變與不變相分離,即產品的組成部分是不變的,但每一部分是可以靈活選擇的。

    通過前面的學習,我們已經了解了建造者模式,那么它和工廠模式有什么區別呢?

    • 建造者模式更加注重方法的調用順序,工廠模式注重創建對象。
    • 創建對象的力度不同,建造者模式創建復雜的對象,由各種復雜的部件組成,工廠模式創建出來的對象都一樣
    • 關注重點不一樣,工廠模式只需要把對象創建出來就可以了,而建造者模式不僅要創建出對象,還要知道對象由哪些部件組成。
    • 建造者模式根據建造過程中的順序不一樣,最終對象部件組成也不一樣。

    優缺點

    該模式的主要優點如下:

    • 封裝性好,構建和表示分離。
    • 擴展性好,各個具體的建造者相互獨立,有利于系統的解耦。
    • 客戶端不必知道產品內部組成的細節,建造者可以對創建過程逐步細化,而不對其它模塊產生任何影響,便于控制細節風險。

    其缺點如下:

    • 產品的組成部分必須相同,這限制了其使用范圍。
    • 如果產品的內部變化復雜,如果產品內部發生變化,則建造者也要同步修改,后期維護成本較大。

    建造者(Builder)模式和工廠模式的關注點不同:建造者模式注重零部件的組裝過程,而工廠方法模式更注重零部件的創建過程,但兩者可以結合使用。

    使用場景

    建造者模式唯一區別于工廠模式的是針對復雜對象的創建。也就是說,如果創建簡單對象,通常都是使用工廠模式進行創建,而如果創建復雜對象,就可以考慮使用建造者模式。

    當需要創建的產品具備復雜創建過程時,可以抽取出共性創建過程,然后交由具體實現類自定義創建流程,使得同樣的創建行為可以生產出不同的產品,分離了創建與表示,使創建產品的靈活性大大增加。

    建造者模式主要適用于以下應用場景:

  • 相同的方法,不同的執行順序,產生不同的結果。
  • 多個部件或零件,都可以裝配到一個對象中,但是產生的結果又不相同。
  • 產品類非常復雜,或者產品類中不同的調用順序產生不同的作用。
  • 初始化一個對象特別復雜,參數多,而且很多參數都具有默認值。
  • 實現

    建造者(Builder)模式的主要角色如下:

  • 產品角色(Product):它是包含多個組成部件的復雜對象,由具體建造者來創建其各個零部件。
  • 抽象建造者(Builder):它是一個包含創建產品各個子部件的抽象方法的接口,通常還包含一個返回復雜產品的方法 getResult()。
  • 具體建造者(Concrete Builder):實現 Builder 接口,完成復雜產品的各個部件的具體創建方法。
  • 指揮者(Director):它調用建造者對象中的部件構造與裝配方法完成復雜對象的創建,在指揮者中不涉及具體產品的信息。
  • package com.atguigu.builder; public class BuilderTest {public static void main(String[] args) {Builder builder1 = new ConcreteBuilder1();Director director = new Director(builder1);Product product = director.construct();product.show();} }class Product {private String partA;private String partB;private String partC;public void setPartA(String partA) {this.partA = partA;}public void setPartB(String partB) {this.partB = partB;}public void setPartC(String partC) {this.partC = partC;}public void show() {//顯示產品的特性System.out.println(this.toString());}@Overridepublic String toString() {return "Product{" +"partA='" + partA + '\'' +", partB='" + partB + '\'' +", partC='" + partC + '\'' +'}';} }abstract class Builder {//創建產品對象protected Product product = new Product();public abstract void buildPartA();public abstract void buildPartB();public abstract void buildPartC();//返回產品對象public Product getResult() {return product;} }class ConcreteBuilder1 extends Builder {public void buildPartA() {product.setPartA("建造 PartA,byBuilder1");}public void buildPartB() {product.setPartB("建造 PartB,byBuilder1");}public void buildPartC() {product.setPartC("建造 PartC,byBuilder1");} }class ConcreteBuilder2 extends Builder {public void buildPartA() {product.setPartA("建造 PartA,byBuilder2");}public void buildPartB() {product.setPartB("建造 PartB,byBuilder2");}public void buildPartC() {product.setPartC("建造 PartC,byBuilder2");} }class Director {private Builder builder;public Director(Builder builder) {this.builder = builder;}//產品構建與組裝方法public Product construct() {builder.buildPartA();builder.buildPartB();builder.buildPartC();return builder.getResult();} }

    總結

    以上是生活随笔為你收集整理的java设计模式(1)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    又色又爽又激情的59视频 | 国产a精品 | 三级av网站 | 婷婷5月激情5月 | 成年一级片 | 日韩在线观看高清 | 在线a亚洲视频播放在线观看 | 欧美日韩国产精品一区 | 久久xx视频 | 午夜少妇av | 在线精品视频免费播放 | www.超碰| 四川bbb搡bbb爽爽视频 | 欧美一级爽 | 狠狠干综合 | 国产精品免费麻豆入口 | 亚洲精品视频在线观看免费视频 | 日韩v欧美v日本v亚洲v国产v | 免费看片日韩 | 综合网婷婷 | 婷婷色中文字幕 | 欧洲视频一区 | www.夜夜草| 丁香狠狠 | 国产手机视频精品 | 久久成人一区二区 | 最新中文字幕视频 | 视频在线观看99 | 国产亚洲视频在线观看 | 国产在线精品一区二区三区 | 婷婷久久久 | av黄网站| 国产伦理久久精品久久久久_ | 一区二区精品在线视频 | 天天操人人要 | 亚洲午夜精品久久久久久久久久久久 | 成人午夜剧场在线观看 | 在线免费av网站 | 天堂网在线视频 | 六月婷婷久香在线视频 | 国产美女视频网站 | 日韩欧美电影在线观看 | 香蕉久久久久久av成人 | 欧美精品首页 | 欧美日韩在线免费观看 | 在线观看香蕉视频 | 国产精品自产拍在线观看桃花 | 一区二区三区在线不卡 | 久久中文网| 国产不卡在线 | 久久99国产综合精品免费 | 日韩三级不卡 | 夜夜狠狠| 国产中文字幕视频在线观看 | 99精品视频一区二区 | 久久久www成人免费精品 | 少妇搡bbb| 最新一区二区三区 | 亚洲一区二区视频在线 | 亚洲精品视频在 | 免费看黄在线看 | 久久久福利视频 | 欧美日韩国产一区二 | 极品久久久久 | 亚洲欧洲xxxx | 日韩视频 一区 | 色婷婷在线播放 | 日韩在线视频一区 | 久久免费电影网 | av高清一区二区三区 | 奇米网在线观看 | 亚洲精品视频免费在线 | 中文字幕一区二区三区乱码不卡 | 国产精品大片在线观看 | 国产高清在线视频 | 亚洲成年人在线播放 | 91亚洲精品国偷拍 | 婷婷丁香色综合狠狠色 | 亚洲国产婷婷 | 摸bbb搡bbb搡bbbb| 国产精品久久久久av | 久久视影 | 亚洲精品日韩av | 日本女人的性生活视频 | 免费av在线网 | 美女免费电影 | 夜夜操天天操 | 中文在线最新版天堂 | 97超碰人人网 | 在线免费黄| 久久久久久草 | 久久福利影视 | 99精品国产一区二区三区不卡 | 精品在线观 | 亚洲国产视频直播 | 成人国产亚洲 | 亚洲电影网站 | 美腿丝袜一区二区三区 | 一区二区三区四区精品视频 | 免费三级黄 | 日韩精品在线观看av | 999视频网站| 最近最新最好看中文视频 | 在线视频久久 | 欧美一区二区三区免费观看 | 黄色免费在线看 | 久久久久久在线观看 | 97在线免费观看视频 | 黄色av网站在线观看免费 | 久久国产精品偷 | 青青草视频精品 | 日韩视频免费播放 | 久草在线手机视频 | 亚洲国产中文字幕在线观看 | 99精品久久久久久久久久综合 | 在线观看的av网站 | 亚洲欧美日韩国产一区二区 | 免费在线观看av的网站 | 国产成在线观看免费视频 | 国产精品9999久久久久仙踪林 | 久草干 | 国产一级二级三级视频 | 日韩精品一区二区三区高清免费 | 久草在线视频网 | 国产成人黄色在线 | 午夜视频一区二区 | 欧美国产大片 | 国产精品福利av | 免费中文字幕在线观看 | 免费视频你懂得 | a视频在线 | 国产精品18久久久久久不卡孕妇 | 69国产盗摄一区二区三区五区 | 天天干夜夜操视频 | 国产二区av | 在线亚洲免费视频 | 国产精品一区二区三区久久久 | 99精品在线视频观看 | 丁香婷婷网| 一区二区 精品 | 99视频久久 | 99视频国产精品免费观看 | 91超级碰 | 一区二区三区四区五区在线 | 中文字幕视频观看 | 国产亚洲一区二区在线观看 | 国产一区成人在线 | 国产裸体无遮挡 | 91精品导航| 久草在线免 | 久久av电影 | 中文一区二区三区在线观看 | 久久久99国产精品免费 | 激情五月亚洲 | 欧美激情精品久久久久久免费 | 午夜精品一区二区三区在线视频 | 美女在线观看av | 亚洲精品视频免费观看 | 狠狠干婷婷| 国产精品视频永久免费播放 | 欧美最爽乱淫视频播放 | 天天做日日做天天爽视频免费 | 九九在线视频免费观看 | 欧美在线视频日韩 | 久久精品国产精品亚洲 | 国产在线观看你懂的 | 在线观看视频日韩 | 国内精品一区二区 | 国产a国产a国产a | 亚洲精品视频大全 | 亚洲天堂毛片 | 久久网站av | 激情影音| 狠狠色丁香久久综合网 | 玖玖视频网 | www,黄视频| 天天狠狠干 | 婷婷开心久久网 | 久草网在线视频 | 久久久五月婷婷 | 国产大尺度视频 | 国产 精品 资源 | 亚洲一区二区三区精品在线观看 | 西西444www大胆无视频 | 精品日韩在线一区 | 97视频在线免费 | 日本论理电影 | 国产视频2区 | 免费一级片观看 | 成年人免费看的视频 | 久久国产美女视频 | 久久久久女人精品毛片九一 | 毛片网站观看 | 国产精品麻豆三级一区视频 | 国产在线视频导航 | 国产精品每日更新 | 国产婷婷在线观看 | 日韩欧美国产精品 | 久久99久久99精品免观看粉嫩 | 黄网站色欧美视频 | 中文字幕在线视频精品 | 午夜精品福利一区二区三区蜜桃 | 天天天操操操 | 日韩系列 | 中文字幕精品www乱入免费视频 | 91丨九色丨蝌蚪丨对白 | 久草在线电影网 | 久要激情网 | 国产理论影院 | 久草在线费播放视频 | 91精品视频免费看 | 国产精品乱码一区二三区 | 99久久99视频只有精品 | 亚洲精品国产精品国自产观看浪潮 | 免费观看黄色av | 成人动漫一区二区三区 | 亚洲欧美日韩国产精品一区午夜 | 欧美日韩国产高清视频 | 日日夜夜免费精品 | 麻豆视频免费在线播放 | 午夜视频免费 | 在线观看www视频 | a级片久久久 | 黄色资源在线 | 9999亚洲 | 中文字幕 第二区 | 992tv人人网tv亚洲精品 | 久久成人精品电影 | 中文字幕av一区二区三区四区 | 欧美综合久久久 | 亚洲区另类春色综合小说 | 色婷婷狠狠18 | 婷婷精品进入 | 黄色一区二区在线观看 | 国产精品一区二区免费看 | 国产成人精品一区在线 | 天天天干天天射天天天操 | 天天爱天天| 国产精品美女视频 | 久久久精品99| 激情视频网页 | 日韩精品久久久久久久电影99爱 | 久久看视频| 亚洲成aⅴ人在线观看 | 久久99精品国产 | 日韩理论片在线观看 | 91精品亚洲影视在线观看 | 欧美日韩精品在线一区二区 | 欧美成人按摩 | 在线免费观看国产黄色 | 日本黄色免费看 | 国产日韩在线看 | 亚洲欧美在线观看视频 | 日韩电影在线观看一区二区三区 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 亚洲精品字幕在线 | 激情视频综合网 | 综合久久综合久久 | av中文资源在线 | 91在线小视频 | 日韩电影中文字幕在线观看 | 国产一区国产二区在线观看 | 超碰av在线 | 日本在线中文在线 | 国产黄免费看 | 色爽网站 | 丁香花在线观看免费完整版视频 | 国产成人久久精品一区二区三区 | 91成人午夜| 996久久国产精品线观看 | 久久99精品久久久久久久久久久久 | 天天色天天上天天操 | 国产无吗一区二区三区在线欢 | 久草视频免费观 | 日韩中文字幕a | 91在线视频免费播放 | 午夜精品三区 | 最近中文字幕高清字幕免费mv | 久久久久久国产精品美女 | 有码中文在线 | 久草在线精品观看 | 毛片网在线观看 | 中文字幕第 | 日韩在线 | 一区二区三区免费看 | 精品国产一区二区三区在线 | 色综合激情久久 | av中文字幕不卡 | av播放在线 | 一区二区三区在线电影 | 欧美精品v国产精品 | 精品一区二区综合 | 五月天中文字幕mv在线 | 美女久久久久 | 三级免费黄色 | 99热高清 | 婷婷激情五月综合 | 日韩剧 | 精品亚洲视频在线 | 青草视频在线免费 | 激情五月六月婷婷 | 五月天丁香视频 | 亚洲欧美精品一区二区 | 亚洲国产精品视频在线观看 | 亚洲三级毛片 | 久久久一本精品99久久精品 | 香蕉视频免费在线播放 | 人人爽人人爽人人片 | 欧美性脚交 | 天天操夜夜操国产精品 | 久久久久久高潮国产精品视 | 成年人电影免费在线观看 | 日韩精品视频在线免费观看 | 久久精品女人毛片国产 | 免费观看av网站 | 亚洲午夜久久久久久久久 | 91麻豆精品国产91久久久无限制版 | 青青草国产精品视频 | 国产美女久久 | 国产亚洲精品久久久久久久久久久久 | 日韩电影久久久 | 国产精品网址在线观看 | 亚洲高清网站 | 亚洲精品综合一区二区 | 在线探花 | 久久激情五月婷婷 | 欧美成人h版电影 | 日韩精品一区二区不卡 | 国产成人黄色在线 | a级片在线播放 | 国产精品av电影 | 亚洲欧洲精品视频 | 视频一区二区在线观看 | 三级小视频在线观看 | 久久精品日产第一区二区三区乱码 | 最近中文字幕免费观看 | 玖玖视频在线 | 亚洲综合色视频在线观看 | 天天干天天天 | 精品高清美女精品国产区 | 欧美一区影院 | 天堂久久电影网 | 国产v在线播放 | 九九九毛片 | 丁香狠狠| 国产成人精品综合 | 麻豆成人在线观看 | 中文字幕日本特黄aa毛片 | 国产中文字幕在线视频 | 天天爱天天操天天干 | 日韩精品一区二区三区水蜜桃 | 成人va天堂 | 日韩精品视频免费在线观看 | 日韩欧美高清一区二区 | 激情丁香5月 | 国产成人久久 | 国产97免费 | 免费aa大片 | 成人av片免费观看app下载 | 亚洲国产精品视频在线观看 | 人人澡人人模 | 亚洲视频一 | 狠狠色噜噜狠狠狠狠2021天天 | 99国产免费网址 | 亚洲伦理电影在线 | 国产高清视频网 | 激情五月***国产精品 | 中文在线a在线 | 婷婷丁香久久五月婷婷 | 亚洲精品国偷拍自产在线观看蜜桃 | 人成在线免费视频 | 1000部国产精品成人观看 | 91成熟丰满女人少妇 | 99超碰在线播放 | 成人黄色视 | 激情综合啪啪 | 91视频啊啊啊 | 国产特级毛片aaaaaa毛片 | 500部大龄熟乱视频使用方法 | 日韩在线观看第一页 | 成人一级免费视频 | 免费在线观看亚洲视频 | 婷婷视频导航 | 日韩免费在线视频 | 国产99一区二区 | 天天干天天操av | 日韩高清片| 国产视频 亚洲视频 | 国产黄色片一级三级 | 91天天操| 人人爽人人爽人人爽 | 奇米导航 | 免费日韩 精品中文字幕视频在线 | 国产成人精品久久二区二区 | 亚洲精品女 | 成av在线 | 国产在线观看你懂得 | 手机看国产毛片 | 免费观看视频黄 | 偷拍精偷拍精品欧洲亚洲网站 | 在线亚洲播放 | 在线观看av中文字幕 | 91片网 | 福利一区在线视频 | 欧美 国产 视频 | 麻豆国产在线播放 | 亚洲开心激情 | 国内外激情视频 | 欧美激情综合五月色丁香 | 久久99久久99精品免观看粉嫩 | 国产视频日韩视频欧美视频 | 久久精品国产免费看久久精品 | 韩国一区二区三区在线观看 | 精品久久久久国产免费第一页 | 超碰国产人人 | 在线视频福利 | 中文字幕日本特黄aa毛片 | 国产亚洲精品久久久久秋 | 亚洲永久国产精品 | 国产高清专区 | 日韩电影在线一区二区 | 亚洲精品乱码久久 | 天天干夜夜操视频 | 国产精国产精品 | 久久字幕精品一区 | 伊人精品影院 | 韩国av在线| 国产在线观看xxx | 三级黄色大片在线观看 | 狠狠色丁香婷婷综合橹88 | 99国产精品一区二区 | 国产在线91精品 | 高潮久久久久久久久 | 亚欧日韩成人h片 | 欧美99热 | 外国av网 | 天堂在线一区 | 美女一级毛片视频 | 成人片在线播放 | 黄色毛片电影 | 亚洲精品五月 | 国产一级视频在线观看 | 色国产精品一区在线观看 | 欧美日本国产在线观看 | 91av在线免费观看 | 久久国产精品二国产精品中国洋人 | 国内精品视频一区二区三区八戒 | 国产玖玖精品视频 | 欧美精品你懂的 | 99久久精品免费看国产四区 | 免费观看成人av | 久久97久久 | 婷婷黄色片 | 三级av网站 | 特级a毛片| 日韩av不卡在线观看 | 不卡的一区二区三区 | 免费视频久久 | 天天想夜夜操 | 91精品在线观看视频 | 日日夜夜天天综合 | 国产一级做a | 又黄又爽又刺激视频 | 欧美久久久久久久久久久久 | 狠狠躁日日躁狂躁夜夜躁 | 99久久综合狠狠综合久久 | 99精品视频在线看 | 久久九九影视 | 国产精品1区 | 日韩欧美成| 99精品视频免费全部在线 | 久青草视频 | 最新国产在线视频 | 欧美日韩国产mv | 亚洲黄色免费观看 | 91九色在线 | 久久福利在线 | 国产成a人亚洲精v品在线观看 | 亚洲成人一区 | 久久丁香 | 97视频免费 | 亚洲成人黄色在线观看 | 久久久首页 | 久久福利 | 国产乱码精品一区二区三区介绍 | 久久99久久99精品中文字幕 | 国产精品不卡视频 | 久久视频这里有久久精品视频11 | 五月婷婷久久综合 | 九九九国产 | 日韩乱理 | 99久久精品免费一区 | 久久久久网站 | av片免费播放 | 日韩精品一区二区三区不卡 | 久久看毛片 | 免费国产在线精品 | 久久精品美女视频 | 9在线观看免费高清完整版 玖玖爱免费视频 | 婷婷综合久久 | 伊人官网 | 欧美贵妇性狂欢 | 99久久99久久综合 | 成人午夜电影网站 | 天天操偷偷干 | 国产男女无遮挡猛进猛出在线观看 | 久草视频在线新免费 | 欧美激情综合五月色丁香 | 狠狠色狠狠色综合日日小说 | 成年人在线观看 | 国产精品亚洲片在线播放 | 91天天操| 国产精品中文 | 日韩精品一区二区三区电影 | 日韩av资源站 | 粉嫩av一区二区三区四区 | 久久综合色影院 | 欧美日韩国产综合一区二区 | 日韩在线二区 | 九九热国产 | 精品美女视频 | 久久久免费高清视频 | 国产免费亚洲 | 麻豆视频免费在线观看 | 日本资源中文字幕在线 | 日本福利视频在线 | 亚洲激情p | 国产中文字幕在线免费观看 | 亚洲午夜精品电影 | 天天干天天干天天干天天干天天干天天干 | 国产精品成人一区二区三区吃奶 | 亚洲人成网站精品片在线观看 | 欧美精品一二三 | 天天干天天操天天射 | av免费在线看网站 | 国产亚洲欧美一区 | 亚洲免费观看视频 | 波多野结衣视频一区二区 | 国产亚洲va综合人人澡精品 | 久久高清毛片 | 欧美精品免费在线观看 | 欧美一级片免费播放 | 亚洲综合在线一区二区三区 | 中文字幕视频播放 | 久久久国产一区二区三区 | 亚洲最新视频在线 | 国产精品久久久区三区天天噜 | 国产精品 999 | 久久久国产精品电影 | 综合色综合色 | 亚洲丁香日韩 | 成人免费观看视频网站 | 婷婷看片| japanesexxxhd奶水| 国产精品久久久久免费a∨ 欧美一级性生活片 | 国产精品麻豆欧美日韩ww | 国产高清视频在线观看 | 久久永久免费视频 | 久草在线综合网 | 久久久av电影 | 日韩视频一区二区 | 久久精品影片 | 国产精品国产亚洲精品看不卡15 | 激情图片区 | 最新精品国产 | 中文字幕av全部资源www中文字幕在线观看 | 韩日精品中文字幕 | 久久视频热 | 久久久精品日本 | 国产一级一片免费播放放a 一区二区三区国产欧美 | 亚洲每日更新 | 亚洲最大成人免费网站 | 521色香蕉网站在线观看 | 亚洲午夜久久久影院 | 欧美日韩中文在线 | 狠狠干网站 | 午夜精品福利一区二区三区蜜桃 | 麻豆视频在线播放 | 亚洲精品日韩一区二区电影 | 中文字幕在线看视频国产中文版 | 欧美一二三区播放 | 天天操天天射天天舔 | 成年人视频在线免费观看 | 98涩涩国产露脸精品国产网 | 伊人五月天 | 免费视频国产 | av福利免费 | 91精品亚洲影视在线观看 | 久久综合色天天久久综合图片 | 欧美日韩国产精品一区二区 | 在线小视频 | 国内精品久久久久久久97牛牛 | 九月婷婷人人澡人人添人人爽 | 亚洲精品久久久久www | 国产精品久久三 | 99久久精品日本一区二区免费 | 99爱爱| 在线播放 亚洲 | 伊人黄 | 高清av中文在线字幕观看1 | 国产免费不卡av | 国产伦精品一区二区三区高清 | 亚洲午夜av久久乱码 | 最新av网站在线观看 | sesese图片| 欧美极度另类性三渗透 | 亚洲精品国产成人av在线 | 欧美日韩另类视频 | 精品国偷自产国产一区 | 日韩xxxx视频 | 精品伦理一区二区三区 | 另类五月激情 | 日本中文字幕影院 | 四虎成人精品永久免费av | 久久激情视频 久久 | 久久与婷婷 | 狠狠色伊人亚洲综合网站野外 | 日韩欧美一区二区三区在线 | 色综合久久久久 | 日韩专区在线播放 | 日韩天天操 | 成人免费视频网 | 成人小电影在线看 | 国产在线 一区二区三区 | 欧美一区二区在线免费观看 | 韩国av三级 | 久久99视频精品 | 久久久一本精品99久久精品66 | 婷婷视频在线播放 | 色欧美视频 | 久久乐九色婷婷综合色狠狠182 | 麻豆成人在线观看 | 成人动漫视频在线 | 亚洲精品午夜国产va久久成人 | 亚洲综合视频在线 | 久久久久久久久久电影 | 久久av免费观看 | 日本午夜在线观看 | 国产v欧美 | 2018精品视频| 欧美日韩国产在线观看 | 国产精品理论片在线播放 | 黄色特级一级片 | 亚洲综合狠狠干 | 中文字幕在线视频一区二区三区 | 97视频在线观看网址 | 在线观看福利网站 | 91视频国产高清 | 成年人免费在线看 | 99色在线观看视频 | 在线观看免费成人 | 久久久999免费视频 日韩网站在线 | 日韩专区视频 | 中文字幕色在线视频 | 亚洲 欧美 综合 在线 精品 | 日本一区二区三区视频在线播放 | a国产精品 | www.久久色 | 最近日韩免费视频 | 久草在线视频看看 | 日韩中文字幕免费视频 | 国产精品一区二区在线观看免费 | 亚洲女人天堂成人av在线 | 丁香综合av| 在线免费观看国产黄色 | 麻豆视频在线免费观看 | 国产成人精品久久久久 | 久久激五月天综合精品 | 91麻豆精品国产91久久久久 | 亚洲高清色综合 | 久久久免费观看完整版 | 久久久久麻豆v国产 | 久久精品系列 | 日韩一级电影网站 | 国产精品理论片在线观看 | 五月天婷婷在线观看视频 | 91中文字幕在线播放 | 国产美女视频免费观看的网站 | av在线网站免费观看 | 欧美日韩免费视频 | 天天综合网天天 | 日韩在线观看视频在线 | 日韩精选在线观看 | 亚洲综合精品在线 | 婷婷综合视频 | 天无日天天操天天干 | 黄色免费网战 | 欧美激情亚洲综合 | 天天射天天干天天 | 激情五月综合 | 91夫妻自拍 | 又紧又大又爽精品一区二区 | 日韩在线色视频 | 国产精品18久久久久久久网站 | 精品黄色片 | 亚洲精品成人av在线 | 日韩欧美综合精品 | 人人澡视频| 亚洲精品午夜久久久久久久 | 亚洲视屏在线播放 | 国产精品资源在线 | 精品96久久久久久中文字幕无 | 麻豆av电影| 日韩一级电影在线观看 | www.玖玖玖| 亚洲激情电影在线 | 亚洲综合婷婷 | 五月天综合色激情 | 日韩精品免费一线在线观看 | 深爱激情久久 | 欧美在线视频不卡 | 国产中的精品av小宝探花 | 成人h在线 | 一二三区视频在线 | 国产精品岛国久久久久久久久红粉 | 国产一级久久久 | 九九九免费视频 | 中文字幕在线播放日韩 | 久久er99热精品一区二区 | 日本黄色免费在线观看 | 一区二区男女 | 国产在线观看免 | 久久久免费观看完整版 | 最近中文字幕 | av免费电影在线观看 | 亚洲高清免费在线 | 最新国产福利 | 蜜桃视频在线视频 | 国产三级视频 | 在线91精品 | 精品国产色 | 日韩在线观看一区二区三区 | 国产一区成人在线 | 黄色大全免费观看 | 久久久久久久久久久高潮一区二区 | 国产中文字幕大全 | 免费成人av电影 | 99久久久国产精品免费观看 | 天天干天天操天天拍 | 中文字幕有码在线观看 | a午夜电影 | 欧美国产不卡 | 在线免费观看麻豆 | 国产精品久久久久久69 | 福利一区在线视频 | 国产精品成人免费精品自在线观看 | 开心丁香婷婷深爱五月 | 91亚洲永久精品 | 欧美在线一二 | 国产精品涩涩屋www在线观看 | 五月亚洲综合 | 久久视频热 | 色婷婷六月 | 日本动漫做毛片一区二区 | 天天天在线综合网 | 久久黄色免费观看 | 又黄又色又爽 | 色七七亚洲影院 | 婷婷丁香激情五月 | 天堂网av 在线 | 天天干天天干天天 | 99久久精品久久久久久动态片 | av激情五月 | 国产在线精品一区二区三区 | 国产精品第三页 | 久久伦理网 | 日韩 精品 一区 国产 麻豆 | 欧美精品v国产精品v日韩精品 | 久久久久久久福利 | 国产精品美女免费视频 | 亚洲精品男女 | 欧美一区二区在线免费看 | 久久久免费视频播放 | 国产高清精品在线观看 | 最近日本mv字幕免费观看 | 亚洲福利精品 | 99这里只有久久精品视频 | 亚洲精品www| 久草剧场| 国产永久免费高清在线观看视频 | 久久精品免费电影 | 欧美小视频在线 | 中文字幕在线播放一区二区 | 久久天天操 | 欧美在线不卡一区 | 超碰免费在线公开 | 欧美一区二区在线 | 亚洲色图美腿丝袜 | 日韩免费电影网 | 日本久久久精品视频 | 999视频网 | 中文在线字幕免费观 | 九九九九精品九九九九 | 亚洲热视频 | 97国产超碰在线 | 西西www444| 婷婷在线资源 | 亚洲四虎在线 | 91成人短视频在线观看 | 最新日韩精品 | 999久久国精品免费观看网站 | 免费在线国产 | 91精品免费在线观看 | 精品国产亚洲在线 | 日韩免费| 国产精品久久久久久久久久免费看 | 久久99在线观看 | 日韩字幕在线观看 | 精品久久久久久久久久久久久久久久久久 | 少妇超碰在线 | 久草热久草视频 | 久久伊人国产精品 | 午夜久久久久久久久久久 | 五月天色网站 | 日韩久久久久久久 | 色狠狠狠 | 欧美精彩视频 | 久久视频在线免费观看 | 在线观看视频色 | 特级西西444www高清大视频 | 91麻豆精品国产91久久久久久久久 | 日韩精品一区二区免费视频 | 久久99精品久久久久久久久久久久 | 亚洲,播放| 91精品欧美 | 久久高清国产视频 | 国产专区第一页 | 美女网站视频一区 | 特级免费毛片 | 久久免费99 | 免费观看黄色av | 91手机视频 | 欧美日韩国产精品一区二区亚洲 | 免费午夜网站 | 免费av观看网站 | 国产精品久久久久毛片大屁完整版 | 中文字幕91视频 | 国产精品第72页 | 人人干免费 | 色婷婷综合久久久久 | 日本女人b | 欧美日韩国产xxx | 中文字幕 二区 | 波多野结衣资源 | 中文字幕在线观 | 丁香婷婷激情国产高清秒播 | ,午夜性刺激免费看视频 | 国产中文自拍 | 国产精品黄色影片导航在线观看 | 丁香六月婷婷开心婷婷网 | 久久精品五月 | 激情文学综合丁香 | 久久精品视频中文字幕 | 97伊人网| 瑞典xxxx性hd极品 | 奇米777777| 国产福利在线免费观看 | 99久久超碰中文字幕伊人 | 国产综合在线观看视频 | 夜夜操狠狠操 | 成人av电影免费在线播放 | 欧美一级性生活片 | 婷婷六月中文字幕 | 干干操操 | 国产午夜麻豆影院在线观看 | 欧美色图另类 | 国产成人精品久久久 | 久久撸在线视频 | 久久精品人 | 国产午夜视频在线观看 | 国产精品免费观看在线 | 日韩网站在线播放 | 亚洲精品久久久久999中文字幕 | 69av网| 99re国产视频| 国产一区二区久久精品 | 激情中文在线 | 欧美日韩精品在线 | 日韩欧美电影网 | 欧美日本一区 | 天天搞天天 | 亚洲黄色小说网 | 久久超碰网 | av片中文字幕 | 正在播放五月婷婷狠狠干 | 欧美一二三区在线观看 | 手机成人在线 | 成人在线网站观看 | 麻豆视频免费入口 | 国产精品一区二区在线观看免费 | 伊人天堂久久 | 中文区中文字幕免费看 | 天天操天天操天天爽 | 日日天天狠狠 | 久久精品99久久久久久2456 | 国产精品一区二区在线免费观看 | 99久久精品国产网站 | 黄色av一级片 | 91chinesexxx| 久久久久久久久久久久久久免费看 | 国产精品影音先锋 | 精品欧美日韩 | 日本久久久久久科技有限公司 | 性色在线视频 | 中文字幕一区二区三区在线播放 | 国产一区免费在线观看 | 亚洲精品在线观看网站 | 激情六月婷婷久久 | 国产爽视频 | 五月天婷婷在线观看视频 | 欧美日韩另类在线 | 日韩激情片在线观看 | 成人中文字幕+乱码+中文字幕 | 欧美日韩高清一区二区三区 | 欧美在线观看视频一区二区三区 | 国产在线一区二区三区播放 | 视频三区在线 | 国产又粗又猛又爽 | 免费h漫在线观看 | 欧美极度另类 | 欧美日韩国产页 | 最近免费中文字幕 | 国产黄色一级大片 | 日韩网站免费观看 | 韩国一区视频 | 久久99久| 亚洲精品国产第一综合99久久 | 久久这里有精品 | 欧美小视频在线 | 91精品国产综合久久久久久久 | 国产在线一区二区三区播放 | 欧美 亚洲 另类 激情 另类 | 精品影院一区二区久久久 | 国产一级大片在线观看 | 午夜精品福利一区二区三区蜜桃 | 亚洲精品国产麻豆 | 天干啦夜天干天干在线线 | 日日日日干 | 91精品久久久久久久久 | 日韩欧美电影网 | 插久久 | 亚洲精品一区二区精华 | 精品在线观看一区二区三区 | 激情综合网天天干 | 成人av亚洲 | www.色的| 91精品国产一区二区三区 | 丁香九月激情综合 | 91超级碰| 99精品在线视频观看 | 国产精品视频内 | 奇米影视8888 | 欧美日韩视频在线一区 | av黄免费看| 亚洲精品999 | 又黄又爽又刺激 | 日韩免费高清在线观看 | 国产在线综合视频 | 91夫妻视频| 91毛片在线 | 99超碰在线观看 | 欧美精品久久99 | 伊人婷婷| 国产成人一区二区三区影院在线 | 亚洲精品h | 久久精品精品电影网 | 亚洲精品久久久久久中文传媒 | 综合久久影院 | 日韩久久电影 | 精品国产乱码久久久久久天美 | 精品乱码一区二区三四区 | 成人a视频在线观看 | 99久久精品国产亚洲 | 久热久草| 亚洲男人天堂a | 色噜噜日韩精品欧美一区二区 | 国产一级二级在线 | 日韩在线观看中文 | 少妇自拍av | 亚洲永久精品在线 | 91精品久久久久 | 国产精品入口66mio女同 | 在线观看香蕉视频 | 久草在线看片 | 国产玖玖在线 | 国产精品成人aaaaa网站 | 在线国产不卡 | 欧美做受高潮1 | 亚洲资源视频 | 九九精品视频在线看 | 国产午夜精品理论片在线 | 久草91视频 | 久久精品视频在线 | 欧美视频二区 | av怡红院| 色婷婷av一区 | 国产伦理久久精品久久久久_ | 黄色成人91 |