国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

網(wǎng)站icp備案 年檢2345網(wǎng)址導(dǎo)航中國最好

網(wǎng)站icp備案 年檢,2345網(wǎng)址導(dǎo)航中國最好,給人做ppt的網(wǎng)站,wordpress自動采集工具Java設(shè)計模式筆記(一) (23種設(shè)計模式由于篇幅較大分為兩篇展示) 一、設(shè)計模式介紹 1、設(shè)計模式的目的 讓程序具有更好的: 代碼重用性可讀性可擴(kuò)展性可靠性高內(nèi)聚,低耦合 2、設(shè)計模式的七大原則 單一職…

Java設(shè)計模式筆記(一)

(23種設(shè)計模式由于篇幅較大分為兩篇展示)

一、設(shè)計模式介紹

1、設(shè)計模式的目的

讓程序具有更好的:

  1. 代碼重用性
  2. 可讀性
  3. 可擴(kuò)展性
  4. 可靠性
  5. 高內(nèi)聚,低耦合

2、設(shè)計模式的七大原則

  1. 單一職責(zé)原則

    一個類只負(fù)責(zé)一項職責(zé),降低類的復(fù)雜度,提高類的可讀性和可維護(hù)性,降低變更引起的風(fēng)險,

  2. 接口隔離原則

    一個類對另一個類的依賴應(yīng)該建立在最小接口上

    在這里插入圖片描述

    上述圖片,類A只需要接口中的1方法,但是卻要實(shí)現(xiàn)2345方法,這就違背了最小接口原則,對其進(jìn)行改進(jìn):

    在這里插入圖片描述

    對接口拆分成幾個獨(dú)立的接口,采用接口隔離原則

  3. 依賴倒置原則

    • 高層模塊不應(yīng)該依賴底層模塊,二者都應(yīng)該依賴其抽象

    • 抽象不應(yīng)該依賴細(xì)節(jié),細(xì)節(jié)應(yīng)該依賴抽象

    • 依賴倒轉(zhuǎn)(倒置)的中心思想是面向接口編程

    • 使用接口或抽象類的目的是制定好規(guī)范,而不涉及任何具體的操作,把展現(xiàn)細(xì)節(jié)的任務(wù)交給他們的實(shí)現(xiàn)類去完成

      如圖所示:

      在這里插入圖片描述

      如果之后有個短信業(yè)務(wù),則需要再person中在加個短信的業(yè)務(wù),對其進(jìn)行改進(jìn)

      在這里插入圖片描述

      引入接口IReceiver,Person類與接口IReceiver發(fā)生依賴關(guān)系,及時之后又短信業(yè)務(wù)也只需要實(shí)現(xiàn)IReceiver接口即可。

  4. 里氏替換原則

    繼承性說明:

    ? 父類中凡是已經(jīng)實(shí)現(xiàn)好的方法,實(shí)際上是在設(shè)定規(guī)范和契約,雖然它不強(qiáng)制要求所有的子類必須遵循這些契約,但是如果子類對這些已經(jīng)實(shí)現(xiàn)的方法任意修改,就會對整個繼承體系造成破壞。

    繼承性弊端:

    ? 使用繼承會給程序帶來侵入性,程序的可移植性降低增加對象間的耦合性,如果一個類被其他的類所繼承,則當(dāng)這個類需要修改時,必須考慮到所有的子類,并且父類修改后,所有涉及到子類的功能都有可能產(chǎn)生

    介紹:

    ? 簡單說就是:所有引用基類的地方必須透明的使用其子類的對象

    ? 在繼承時,子類中盡量不要重寫父類中的方法

    在這里插入圖片描述

    上圖中,父類中的add方法是a+b,但是子類B重寫了父類的add方法將其改為了a-b,當(dāng)程序調(diào)用的時候可能會出現(xiàn)錯誤。

    在這里插入圖片描述

    采用依賴、聚合、組合的方法替換,抽取一個共同的父類,在使用C的時候還可使用B的原始方法。

    1、創(chuàng)建一個基類

    class Base {}
    

    2、A類

    class A extends Base {public int fun1(int a, int b) {return a+b;}
    }
    

    3、B類

    class B extends Base {private A a = new A();// 寫自己的方法public int fun1(int a, int b) {return a+b;}// 仍然使用A的方法public int fun2(int a, int b) {return this.a.fun1(a,b);}
    }
    
  5. 開閉原則

    ? 是編程中最基礎(chǔ)、最重要的設(shè)計原則;當(dāng)軟件需要修改時,盡量通過擴(kuò)展軟件實(shí)體的行為來實(shí)現(xiàn)變化,而不是通過修改已有的代碼來實(shí)現(xiàn)變化。

    在這里插入圖片描述

    代碼演示:

    //這是一個用于繪圖的類
    class GraphicEditor {//接收 Shape 對象,然后根據(jù) type,來繪制不同的圖形public void drawShape(Shape s){if(s.m_type=-1)drawRectangle(s);else if(s.m type-2)drawCircle(s);else if(s.m_type - 3)drawTriangle(s)}//繪制矩形public void drawRectangle(Shape r){System.out.printn(”繪制矩形");}//繪制圓形public void drawCircle(Shape r){System.out.println("繪制圓形");}//繪制三角形public void drawTriangle(Shape r){System.out.println(”繪制三角形");}
    }//Shape 類,基類
    class Shape {int m_type;
    }class Rectangle extends Shape {Rectangle(){super.m_type=1;}
    }class Circle extends Shape {Circle() {super.m_type =2;}
    }//新增畫三角形
    class Triangle extends Shape {Triangle() {super.m_type = 3;}
    }// 開始調(diào)用
    public class Ocp {public static void main(Stringll args){//使用看看存在的問題GraphicEditor graphicEditor = new GraphicEditor();graphicEditor.drawShape(new Rectangle());graphicEditor.drawShape(new Circle());graphicEditor.drawShape(new Triangle());}
    }
    

    上述代碼的優(yōu)缺點(diǎn):

    ? 1、比較好理解

    ? 2、缺點(diǎn)就是違反了設(shè)計模式的ocp原則。即對擴(kuò)展開放,對修改關(guān)閉,當(dāng)要新增功能時GraphicEditor需要做修改。

    改進(jìn):

    ? 把創(chuàng)建 Shape 類做成抽象類,并提供一個抽象的 draw方法,讓子類去實(shí)現(xiàn)即可,這樣我們有新的圖形種類時,只需要讓新的圖形類繼承 Shape,并實(shí)現(xiàn) draw方法即可,使用方的代碼就不需要修 -> 滿足了開閉原則

    //這是一個用于繪圖的類
    class GraphicEditor {//接收 Shape 對象調(diào)用draw方法public void drawShape(Shape s){s.draw();}
    }//Shape 類,基類
    abstract class Shape {int m_type;public abstract void draw();//抽象方法
    }class Rectangle extends Shape {Rectangle(){super.m_type=1;}@Overridepublic void draw(){// TODO Auto-generated method stubSystem.out.println("繪制矩形");}
    }class Circle extends Shape {Circle() {super.m_type =2;}@Overridepublic void draw(){// TODO Auto-generated method stubSystem.out.println("繪制圓形");}
    }//新增畫三角形
    class Triangle extends Shape {Triangle() {super.m_type = 3;}@Overridepublic void draw(){// TODO Auto-generated method stubSystem.out.println("繪制三角形");}
    }// 開始調(diào)用
    public class Ocp {public static void main(Stringll args){//使用看看存在的問題GraphicEditor graphicEditor = new GraphicEditor();graphicEditor.drawShape(new Rectangle());graphicEditor.drawShape(new Circle());graphicEditor.drawShape(new Triangle());}
    }
    
  6. 迪米特法則

    ? 迪米特法則(Demeter Principle)又叫最少知道原則,即一個類對自己依賴的類知道的越少越好。也就是說,對于被依賴的類不管多么復(fù)雜,都盡量將邏輯封裝在類的內(nèi)部。對外除了提供的 public 方法,不對外泄露任何信息。

  7. 合成復(fù)用原則

    盡量使用合成/聚合的方式,而不是使用繼承;

二、設(shè)計模式概述

1、介紹

? 設(shè)計模式是程序員在面對同類軟件工程設(shè)計問題所總結(jié)出來的有用的經(jīng)驗(yàn),模式不是代碼,而是某類問題的通用解決方案,設(shè)計模式(Design patern)代表了最佳的實(shí)踐。這些解決方案是眾多軟件開發(fā)人員經(jīng)過相當(dāng)長的一段時間的試驗(yàn)和錯誤總結(jié)出來的。
? 設(shè)計模式的本質(zhì)提高軟件的維護(hù)性,通用性和擴(kuò)展性,并降低軟件的復(fù)雜度

2、設(shè)計模式類型

設(shè)計模式分為三種類型,共 23種

1)創(chuàng)建型模式:單例模式、抽象工廠模式、原型模式、建造者模式、工廠模式。

2)結(jié)構(gòu)型模式:適配器模式、橋接模式、裝飾模式、組合模式、外觀模式、享元模式、代理模式。

3)行為型模式:模版方法模式、命令模式、訪問者模式、迭代器模式、觀察者模式、中介者模式、備忘錄模式.解釋器模式(Interpreter 模式)、狀態(tài)模式、策略模式、職責(zé)鏈模式(責(zé)任鏈模式)。

三、單例設(shè)計模式

1、介紹

? 所謂類的單例設(shè)計模式,就是采取一定的方法保證在整個的軟件系統(tǒng)中,對某個類只能存在一個對象實(shí)例,并且該類只提供一個取得其對象實(shí)例的方法(靜態(tài)方法)。

2、單例模式的8種方式

  • 餓漢式(靜態(tài)常量)
  • 餓漢式(靜態(tài)代碼塊)
  • 懶漢式(線程不安全)
  • 懶漢式(線程安全,同步方法)
  • 懶漢式(線程安全,同步代碼塊)
  • 雙重檢查
  • 靜態(tài)內(nèi)部類
  • 枚舉
(1)餓漢式(靜態(tài)常量)

實(shí)現(xiàn)步驟:

  • 構(gòu)造器私有化(防止 new )

  • 類的內(nèi)部創(chuàng)建對象

  • 向外暴露一個靜態(tài)的公共方法。getlnstance

  • 代碼實(shí)現(xiàn)

//餓漢式(靜態(tài)變量)
class Singleton {//1.構(gòu)造器私有化,外部能 newprivate Singleton() {}//2.本類內(nèi)部創(chuàng)建對象實(shí)例private final static Singleton instance = new Singleton().//3.提供一個公有的靜態(tài)方法,返回實(shí)例對象public static Singleton getInstance(){return instance;}
}public class SingletonTest {public static void main(String|largs){//測試Singleton instance = Singleton.getInstance();Singleton instance2 = Singleton.getInstance();System.out.println(instance == instance2); // trueSystem.out.println("instance.hashCode=" + instance .hashCode());System.out.println("instance2.hashCode=" + instance2.hashCode()):}
}

說明:

1)優(yōu)點(diǎn):這種寫法比較簡單,就是在類裝載的時候就完成實(shí)例化。避免了線程同步問題。

2)缺點(diǎn):在類裝載的時候就完成實(shí)例化,沒有達(dá)到LazyLoading 的效果。如果從始至終從未使用過這個實(shí)例,則 會造成內(nèi)存的浪費(fèi)

3)這種方式基于 classloder 機(jī)制避免了多線程的同步問題,不過,instance 在類裝載時就實(shí)例化,在單例模式中大多數(shù)都是調(diào)用 getnstance方法,但是導(dǎo)致類裝載的原因有很多種,因此不能確定有其他的方式(或者其他的靜態(tài)方法)導(dǎo)致類裝載,這時候初始化instance 就沒有達(dá)到 lazy loading 的效果

(2)餓漢式(靜態(tài)代碼塊)
public class Singleton {//1.構(gòu)造器私有化,外部能 newprivate Singleton(){}//2.本類內(nèi)部創(chuàng)建實(shí)例對象private static Singleton instance;//3. 在靜態(tài)代碼塊中創(chuàng)建單例對象static {instance = new Singleton();}// 4.提供一個公有的靜態(tài)方法,返回實(shí)例對象public static Singleton getInstance (){return instance;}}

說明:

1)這種方式和上面的方式其實(shí)類似,只不過將類實(shí)例化的過程放在了靜態(tài)代碼塊中,也是在類裝載的時候,就執(zhí)行靜態(tài)代碼塊中的代碼,初始化類的實(shí)例。優(yōu)缺點(diǎn)和上面是一樣的。

2)這種單例模式可用,但是可能造成內(nèi)存浪費(fèi)

(3)懶漢式(線程不安全)
public class Singleton {//1.構(gòu)造器私有化,外部能 newprivate Singleton(){}//2.本類內(nèi)部創(chuàng)建實(shí)例對象private static Singleton instance;//3. 提供一個靜態(tài)公有方法,當(dāng)使用到該方法時,才去創(chuàng)建instancepublic static Singleton getInstance (){if (instance == null) {instance = new Singleton();}return instance;}}

說明:

1)起到了 Lazy Loading的效果,但是只能在單線程下使用。

2)如果在多線程下,一個線程進(jìn)入了 if(singleton ==nul)判斷語句塊,還未來得及往下執(zhí)行,另一個線程也通過了這個判斷語句,這時便會產(chǎn)生多個實(shí)例。所以在多線程環(huán)境下不可使用這種方式

3)在實(shí)際開發(fā)中,不要使用這種方式

(4)懶漢式(線程安全,同步方法)
public class Singleton {//1.構(gòu)造器私有化,外部能 newprivate Singleton(){}//2.本類內(nèi)部創(chuàng)建實(shí)例對象private static Singleton instance;//3. 提供一個靜態(tài)公有方法,加synchronized關(guān)鍵詞保證線安全,當(dāng)使用到該方法時,才去創(chuàng)建instancepublic static synchronized Singleton getInstance (){if (instance == null) {instance = new Singleton();}return instance;}}

說明:

1)解決了線程安全問題

2)效率太低了,每個線程在想獲得類的實(shí)例時候,執(zhí)行 getinstance()方法都要進(jìn)行同步。而其實(shí)這個方法只執(zhí)行一次實(shí)例化代碼就夠了,后面的想獲得該類實(shí)例,直接retumn 就行了。方法進(jìn)行同步效率太低

3)在實(shí)際開發(fā)中,不推薦使用這種方式

(5)懶漢式(線程安全,同步代碼塊)
public class Singleton {//1.構(gòu)造器私有化,外部能 newprivate Singleton(){}//2.本類內(nèi)部創(chuàng)建實(shí)例對象private static Singleton instance;//3. 提供一個靜態(tài)公有方法,當(dāng)使用到該方法時,才去創(chuàng)建instancepublic static Singleton getInstance (){if (instance == null) {// 添加同步代碼塊synchronized (Singleton.class) {instance = new Singleton();}}return instance;}}

不推薦使用

(6)雙重檢查
public class Singleton {//1.構(gòu)造器私有化,外部能 newprivate Singleton(){}//2.本類內(nèi)部創(chuàng)建實(shí)例對象private static volatile Singleton instance;//3.提供一個靜態(tài)的公有方法,加入雙重檢査代碼,解決線程安全問題,同時解決懶加載問題,同同時保證了效率,推薦使用public static Singleton getInstance (){if (instance == null) {// 添加同步代碼塊synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}}

說明:

1)Double-Check概念是多線程開發(fā)中常使用到的,如代碼中所示,我們進(jìn)行了兩次 if(singleton == nul)檢查,這樣就可以保證線程安全了。

2)實(shí)例化代碼只用執(zhí)行一次,后面再次訪問時,判斷if(singleton= null),直接retum 實(shí)例化對象,也避免反復(fù)進(jìn)行方法同步

3)線程安全;延遲加載;效率較高

4)在實(shí)際開發(fā)中推薦使用這種單例設(shè)計模式

(7)靜態(tài)內(nèi)部類
public class Singleton {//1.構(gòu)造器私有化,外部能 newprivate Singleton(){}//2.靜態(tài)內(nèi)部類private static class SingletonInstance {private static final Singleton INSTANCE = new Singleton();}//3.提供一個靜態(tài)的公有方法,直接返回INSTANCE,推薦使用public static Singleton getInstance (){return SingletonInstance.INSTANCE;}}

說明:

1)這種方式采用了類裝載的機(jī)制來保證初始化實(shí)例時只有一個線程。

2)靜態(tài)內(nèi)部類方式在 Singleton 類被裝載時并不會立即實(shí)例化,而是在需要實(shí)例化時,調(diào)用 getnstance 方法,才會裝載 SingletonInstance 類,從而完成 Singleton 的實(shí)例化。

3)類的靜態(tài)屬性只會在第一次加載類的時候初始化,所以在這里,JVM 幫助我們保證了線程的安全性,在類進(jìn)行初始化時,別的線程是無法進(jìn)入的。

4)避免了線程不安全,利用靜態(tài)內(nèi)部類特點(diǎn)實(shí)現(xiàn)延遲加載,效率高

5)推薦使用

(8)枚舉
// 枚舉形式
public enum Singleton2 {INSTANCE;
}public static void main(String[] args) {Singleton2 instance = Singleton2.INSTANCE;Singleton2 instance2 = Singleton2.INSTANCE;System.out.println(instance == instance2);System.out.println(instance.hashCode());System.out.println(instance2.hashCode());
}

說明:

1)這借助JDK15 中添加的枚舉來實(shí)現(xiàn)單例模式。不僅能避免多線程同步問題,而且還能防止反序列化重新創(chuàng)建1)新的對象。

2)這種方式是 Effective Java 作者 Josh Bloch 提倡的方式

3)推薦使用

3、單例模式在jdk中的使用

java.lang.RunTime就是經(jīng)典的單例惡漢模式

在這里插入圖片描述

4、注意事項

1)單例模式保證了 系統(tǒng)內(nèi)存中該類只存在一個對象,節(jié)省了系統(tǒng)資源,對于一些需要頻繁創(chuàng)建銷毀的對象,使用單例模式可以提高系統(tǒng)性能

2)當(dāng)想實(shí)例化一個單例類的時候,必須要記住使用相應(yīng)的獲取對象的方法,而不是使用 new

3)單例模式使用的場景:

? 需要頻繁的進(jìn)行創(chuàng)建和銷毀的對象、創(chuàng)建對象時耗時過多或耗費(fèi)資源過多(即:重量級對象),但又經(jīng)常用到的對象、工具類對象、頻繁訪問數(shù)據(jù)庫或文件的對象(比如數(shù)據(jù)源、session 工廠等)

四、工廠模式

1、分類

  • 簡單工廠模式
  • 工廠方法模式
  • 抽象工廠模式

2、簡單工廠模式

(1)介紹

1)簡單工廠模式是屬于創(chuàng)建型模式,是工廠模式的一種。簡單工廠模式是由一個工廠對象決定創(chuàng)建出哪一種產(chǎn)品類的實(shí)例。簡單工廠模式是工廠模式家族中最簡單實(shí)用的模式

2)簡單工廠模式定義了一個創(chuàng)建對象的類,由這個類來封裝實(shí)例化對象的行為(代碼)

3)在軟件開發(fā)中,當(dāng)我們會用到大量的創(chuàng)建某種類或者某批對象時,就會使用到工廠模式

(2)案例

披薩的項目:要便于披薩種類的擴(kuò)展,要便于維護(hù)

  • 披薩的種類很多(比如 GreekPizz、CheesePizz 等)
  • 披薩的制作有 prepare,bake,cut, box
  • 完成披薩店訂購功能。

1、創(chuàng)建一個pizza類

//將Pizza 類做成抽象
public abstract class Pizza {protected String name; //名字//準(zhǔn)備原材料, 不同的披薩不一樣,因此,我們做成抽象方法public abstract void prepare();public void bake() {System.out.println(name + " baking;");}public void cut() {System.out.println(name + " cutting;");}//打包public void box() {System.out.println(name + " boxing;");}public void setName(String name) {this.name = name;}
}

2、希臘披薩類

public class GreekPizza extends Pizza {@Overridepublic void prepare() {// TODO Auto-generated method stubSystem.out.println("給【希臘披薩】準(zhǔn)備原材料");}}

3、奶酪pizza

public class CheesePizza extends Pizza {@Overridepublic void prepare() {// TODO Auto-generated method stubSystem.out.println(" 給制作奶酪披薩 準(zhǔn)備原材料 ");}}

4、簡單工廠類

public class SimpleFactory {//根據(jù)orderType 返回對應(yīng)的Pizza 對象public Pizza createPizza(String orderType) {Pizza pizza = null;System.out.println("使用簡單工廠模式");if (orderType.equals("greek")){pizza = new GreekPizza();pizza.setName(" 希臘披薩 ");} else if (orderType.equals("cheese")){pizza = new CheesePizza();pizza.setName(" 奶酪披薩 ");}return pizza;}//簡單工廠模式 也叫 靜態(tài)工廠模式public static Pizza createPizza2(String orderType) {Pizza pizza = null;System.out.println("使用簡單工廠模式2");if (orderType.equals("greek")) {pizza = new GreekPizza();pizza.setName(" 希臘披薩 ");} else if (orderType.equals("cheese")) {pizza = new CheesePizza();pizza.setName(" 奶酪披薩 ");}return pizza;}
}

5、訂購pizza

public class OrderPizza {//定義一個簡單工廠對象SimpleFactory simpleFactory;Pizza pizza;String orderType;//構(gòu)造器public OrderPizza(SimpleFactory simpleFactory, String orderType){this.simpleFactory = simpleFactory;this.orderType = orderType;setFactory();}private void setFactory() {// 根據(jù)用戶輸入的類型獲取隊形的pizza對象pizza = simpleFactory.createPizza(orderType);//輸出pizzaif(pizza != null) { //訂購成功pizza.prepare();pizza.bake();pizza.cut();pizza.box();} else {System.out.println(" 訂購披薩失敗 ");}}}

6、測試

    public static void main(String[] args) {//使用簡單工廠模式new OrderPizza(new SimpleFactory(), "greek");}
輸出:使用簡單工廠模式
給【希臘披薩】準(zhǔn)備原材料希臘披薩  baking;希臘披薩  cutting;希臘披薩  boxing; 

如果之后需要增加pizza類型,只需要在工廠中追加即可

3、工廠方法模式

(1)介紹

工廠方法模式:定義了一個創(chuàng)建對象的抽象方法,由子類決定要實(shí)例化的類。工廠方法模式將對象的實(shí)例化推遲到子類。

(2)案例

披薩項目新的需求:客戶在點(diǎn)披薩時,可以點(diǎn)不同口味的披薩,比如 北京的奶酪 pizza、北京的胡椒 pizza 或者是倫敦的奶酪 pizza、倫敦的胡椒 pizza

在這里插入圖片描述

1、將Pizza 類做成抽象

//將Pizza 類做成抽象
public abstract class Pizza {protected String name; //名字//準(zhǔn)備原材料, 不同的披薩不一樣,因此,我們做成抽象方法public abstract void prepare();public void bake() {System.out.println(name + " baking;");}public void cut() {System.out.println(name + " cutting;");}//打包public void box() {System.out.println(name + " boxing;");}public void setName(String name) {this.name = name;}
}

2、北京奶酪pizza

public class BJCheesePizza extends Pizza {@Overridepublic void prepare() {setName("北京的奶酪pizza");System.out.println(" 北京的奶酪pizza 準(zhǔn)備原材料");}}

3、北京胡椒pizza

public class BJPepperPizza extends Pizza {@Overridepublic void prepare() {// TODO Auto-generated method stubsetName("北京的胡椒pizza");System.out.println(" 北京的胡椒pizza 準(zhǔn)備原材料");}
}

4、倫敦奶酪pizza

public class LDCheesePizza extends Pizza{@Overridepublic void prepare() {// TODO Auto-generated method stubsetName("倫敦的奶酪pizza");System.out.println(" 倫敦的奶酪pizza 準(zhǔn)備原材料");}
}

5、倫敦胡椒pizza

public class LDPepperPizza extends Pizza{@Overridepublic void prepare() {// TODO Auto-generated method stubsetName("倫敦的胡椒pizza");System.out.println(" 倫敦的胡椒pizza 準(zhǔn)備原材料");}
}

6、訂購pizza抽象類

public abstract class OrderPizza {//定義一個抽象方法,createPizza , 讓各個工廠子類自己實(shí)現(xiàn)abstract Pizza createPizza(String orderType);// 構(gòu)造器public OrderPizza(String orderType) {Pizza pizza = createPizza(orderType); //抽象方法,由工廠子類完成//輸出pizza 制作過程pizza.prepare();pizza.bake();pizza.cut();pizza.box();}}

7、訂購北京pizza

public class BJOrderPizza extends OrderPizza {public BJOrderPizza(String orderType) {super(orderType);}@OverridePizza createPizza(String orderType) {Pizza pizza = null;if(orderType.equals("cheese")) {pizza = new BJCheesePizza();} else if (orderType.equals("pepper")) {pizza = new BJPepperPizza();}// TODO Auto-generated method stubreturn pizza;}}

8、訂購倫敦pizza

public class LDOrderPizza extends OrderPizza {public LDOrderPizza(String orderType) {super(orderType);}@OverridePizza createPizza(String orderType) {Pizza pizza = null;if(orderType.equals("cheese")) {pizza = new LDCheesePizza();} else if (orderType.equals("pepper")) {pizza = new LDPepperPizza();}// TODO Auto-generated method stubreturn pizza;}}

9、測試

    public static void main(String[] args) {new LDOrderPizza("cheese");}
// ==================================================倫敦的奶酪pizza 準(zhǔn)備原材料
倫敦的奶酪pizza baking;
倫敦的奶酪pizza cutting;
倫敦的奶酪pizza boxing;

說明:

? 如果后期要加一個北京西紅柿pizza,只需要先實(shí)現(xiàn)Pizza抽象類,可以寫具體的實(shí)現(xiàn)過程,再在BJOrderPizza類中加一個判斷條件。

4、抽象工廠模式

(1)介紹

1)抽象工廠模式:定義了一個interface 用于創(chuàng)建相關(guān)或有依賴關(guān)系的對象簇,而無需指明具體的類

2)抽象工廠模式可以將簡單工廠模式和工廠方法模式進(jìn)行整合。

3)從設(shè)計層面看,抽象工廠模式就是對簡單工廠模式的改進(jìn)(或者稱為進(jìn)一步的抽象)。

4)將工廠抽象成兩層,AbsFactory(抽象工廠)和 具體實(shí)現(xiàn)的工廠子類。根據(jù)創(chuàng)建對象類型使用對應(yīng)的工廠子類。這樣將單個的簡單工廠類變成了工廠簇,更利于代碼的維護(hù)和擴(kuò)展。

在這里插入圖片描述

(2)案例

12345使用工廠方法模式代碼

6、抽象工廠模式抽象層

//一個抽象工廠模式的抽象層(接口)
public interface AbsFactory {//讓下面的工廠子類來 具體實(shí)現(xiàn)public Pizza createPizza(String orderType);
}

7、北京工廠類

//這是工廠子類
public class BJFactory implements AbsFactory {public Pizza createPizza(String orderType) {System.out.println("~使用的是抽象工廠模式~");// TODO Auto-generated method stubPizza pizza = null;if(orderType.equals("cheese")) {pizza = new BJCheesePizza();} else if (orderType.equals("pepper")){pizza = new BJPepperPizza();}return pizza;}
}

8、倫敦工廠類

public class LDFactory implements AbsFactory {public Pizza createPizza(String orderType) {System.out.println("~使用的是抽象工廠模式~");Pizza pizza = null;if (orderType.equals("cheese")) {pizza = new LDCheesePizza();} else if (orderType.equals("pepper")) {pizza = new LDPepperPizza();}return pizza;}}

9、訂購pizza類

public class OrderPizza {AbsFactory factory;// 構(gòu)造器public OrderPizza(AbsFactory factory, String orderType) {setFactory(factory,orderType);}private void setFactory(AbsFactory factory, String orderType) {Pizza pizza = null;this.factory = factory;// factory 可能是北京的工廠子類,也可能是倫敦的工廠子類pizza = factory.createPizza(orderType);if (pizza != null) { // 訂購okpizza.prepare();pizza.bake();pizza.cut();pizza.box();} else {System.out.println("訂購失敗");}}}

10、測試

	public static void main(String[] args) {new OrderPizza(new BJFactory(), "cheese");}
// ===========================================================
~使用的是抽象工廠模式~北京的奶酪pizza 準(zhǔn)備原材料
北京的奶酪pizza baking;
北京的奶酪pizza cutting;
北京的奶酪pizza boxing;

5、總結(jié)

1)將實(shí)例化對象的代碼提取出來,放到一個類中統(tǒng)一管理和維護(hù),達(dá)到和主項目的依賴關(guān)系的解耦。從而提高項目的擴(kuò)展和維護(hù)性。

2)創(chuàng)建對象實(shí)例時,不要直接 new 類,而是把這個 new 類的動作放在一個工廠的方法中,并返回。

3)不要讓類繼承具體類,而是繼承抽象類或者是實(shí)現(xiàn)interface(接口)不要覆蓋基類中已經(jīng)實(shí)現(xiàn)的方法。

五、原型模式

1、介紹

1)原型模式(Prototype 模式)是指:用原型實(shí)例指定創(chuàng)建對象的種類,并且通過拷貝這些原型,創(chuàng)建新的對象

2)原型模式是一種創(chuàng)建型設(shè)計模式,允許一個對象再創(chuàng)建另外一個可定制的對象,無需知道如何創(chuàng)建的細(xì)節(jié)

3)工作原理是:將一個原型對象傳給那個要發(fā)動創(chuàng)建的對象,這個要發(fā)動創(chuàng)建的對象通過請求原型對象拷貝它們自己來實(shí)施創(chuàng)建,即 對象.clone()

2、案例

基礎(chǔ)類

public class Sheep implements Cloneable {private String name;private int age;private String color;public Sheep friend; //是對象, 克隆是會如何處理public Sheep(String name, int age, String color) {super();this.name = name;this.age = age;this.color = color;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}@Overridepublic String toString() {return "Sheep [name=" + name + ", age=" + age + ", color=" + color + "]";}//克隆該實(shí)例,使用默認(rèn)的clone方法來完成@Overrideprotected Object clone()  {Sheep sheep = null;try {sheep = (Sheep)super.clone();} catch (Exception e) {// TODO: handle exceptionSystem.out.println(e.getMessage());}// TODO Auto-generated method stubreturn sheep;}}

測試類

    public static void main(String[] args) {Sheep sheep = new Sheep("白羊", 5, "白色");sheep.friend = new Sheep("jack", 2, "黑色");Sheep sheep1 = (Sheep) sheep.clone();Sheep sheep2 = (Sheep) sheep.clone();Sheep sheep3 = (Sheep) sheep.clone();System.out.println(sheep1 + "    friend-hash: " + sheep1.friend.hashCode());System.out.println(sheep2 + "    friend-hash: " + sheep2.friend.hashCode());System.out.println(sheep3 + "    friend-hash: " + sheep3.friend.hashCode());}

輸出:

Sheep [name=白羊, age=5, color=白色] friend-hash: 460141958
Sheep [name=白羊, age=5, color=白色] friend-hash: 460141958
Sheep [name=白羊, age=5, color=白色] friend-hash: 460141958

發(fā)現(xiàn)在克隆sheep時,應(yīng)用類型的friend只是做了淺拷貝

3、淺拷貝介紹

1)對于數(shù)據(jù)類型是基本數(shù)據(jù)類型的成員變量,淺拷貝會直接進(jìn)行值傳遞,也就是將該屬性值復(fù)制一份給新的對象。

2)對于數(shù)據(jù)類型是引用數(shù)據(jù)類型的成員變量,比如說成員變量是某個數(shù)組、某個類的對象等,那么淺拷貝會進(jìn)行引用傳遞,也就是將該成員變量的引用值(內(nèi)存地址)復(fù)制一份給新的對象。因?yàn)閷?shí)際上兩個對象的該成員變量都指向同一個實(shí)例。在這種情況下,在一個對象中修改該成員變量會影響到另一個對象的該成員變量值;在上述案例中就是淺拷貝。

3)淺拷貝是使用默認(rèn)的 clone()方法來實(shí)現(xiàn)

? sheep=(Sheep) super.clone():

4、深拷貝介紹

1)復(fù)制對象的所有基本數(shù)據(jù)類型的成員變量值

2)為所有引用數(shù)據(jù)類型的成員變量申請存儲空間,并復(fù)制每個引用數(shù)據(jù)類型成員變量所引用的對象,直到該對象可達(dá)的所有對象。也就是說,對象進(jìn)行深拷貝要對整個對象(包括對象的引用類型)進(jìn)行拷貝

3)深拷貝實(shí)現(xiàn)方式 :重寫clone方法來實(shí)現(xiàn)深拷貝

4)深拷貝實(shí)現(xiàn)方式:通過對象序列化實(shí)現(xiàn)深拷貝(推薦)

5) 案例

基本類型

public class DeepCloneableTarget implements Serializable, Cloneable {private static final long serialVersionUID = 1L;private String cloneName;private String cloneClass;//構(gòu)造器public DeepCloneableTarget(String cloneName, String cloneClass) {this.cloneName = cloneName;this.cloneClass = cloneClass;}//因?yàn)樵擃惖膶傩?#xff0c;都是String , 因此我們這里使用默認(rèn)的clone完成即可@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}

引用類型

public class DeepProtoType implements Serializable, Cloneable{public String name; //String 屬性public DeepCloneableTarget deepCloneableTarget;// 引用類型public DeepProtoType() {super();}//深拷貝 - 方式 1 使用clone 方法// 缺陷:如果引用類型屬性的內(nèi)部屬性還是應(yīng)用類型。則其內(nèi)部的應(yīng)用類型也要重寫clone@Overrideprotected Object clone() throws CloneNotSupportedException {Object deep = null;//這里完成對基本數(shù)據(jù)類型(屬性)和String的克隆deep = super.clone(); //對引用類型的屬性,進(jìn)行單獨(dú)處理DeepProtoType deepProtoType = (DeepProtoType)deep;deepProtoType.deepCloneableTarget  = (DeepCloneableTarget)deepCloneableTarget.clone();// TODO Auto-generated method stubreturn deepProtoType;}//深拷貝 - 方式2 通過對象的序列化實(shí)現(xiàn) (推薦)public Object deepClone() {//創(chuàng)建流對象ByteArrayOutputStream bos = null;ObjectOutputStream oos = null;ByteArrayInputStream bis = null;ObjectInputStream ois = null;try {//序列化bos = new ByteArrayOutputStream();oos = new ObjectOutputStream(bos);oos.writeObject(this); //當(dāng)前這個對象以對象流的方式輸出//反序列化bis = new ByteArrayInputStream(bos.toByteArray());ois = new ObjectInputStream(bis);DeepProtoType copyObj = (DeepProtoType)ois.readObject();return copyObj;} catch (Exception e) {// TODO: handle exceptione.printStackTrace();return null;} finally {//關(guān)閉流try {bos.close();oos.close();bis.close();ois.close();} catch (Exception e2) {// TODO: handle exceptionSystem.out.println(e2.getMessage());}}}}

測試

	public static void main(String[] args) {// TODO Auto-generated method stubDeepProtoType p = new DeepProtoType();p.name = "李四";p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛");//方式2 完成深拷貝DeepProtoType p2 = (DeepProtoType) p.deepClone();System.out.println("p.name=" + p.name + "		p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());System.out.println("p2.name=" + p.name + "		p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());}

結(jié)果

p.name=李四 p.deepCloneableTarget=1836019240
p2.name=李四 p2.deepCloneableTarget=363771819

5、總結(jié)

1)創(chuàng)建新的對象比較復(fù)雜時,可以利用原型模式簡化對象的創(chuàng)建過程,同時也能夠提高效率

2)不用重新初始化對象,而是動態(tài)地獲得對象運(yùn)行時的狀態(tài)

3)如果原始對象發(fā)生變化(增加或者減少屬性),其它克隆對象的也會發(fā)生相應(yīng)的變化,無需修改代碼

4)在實(shí)現(xiàn)深克隆的時候可能需要比較復(fù)雜的代碼

5)缺點(diǎn):需要為每一個類配備一個克隆方法,這對全新的類來說不是很難,但對已有的類進(jìn)行改造時,需要修改其源代碼,違背了 ocp 原則。

六、建造者模式

1、介紹

1)建造者模式(Builder Pattern) 又叫生成器模式,是一種對象構(gòu)建模式。它可以將復(fù)雜對象的建造過程抽象出來(抽象類別),使這個抽象過程的不同實(shí)現(xiàn)方法可以構(gòu)造出不同表現(xiàn)(屬性)的對象。

2)建造者模式 是一步一步創(chuàng)建一個復(fù)雜的對象,它允許用戶只通過指定復(fù)雜對象的類型和內(nèi)容就可以構(gòu)建它們,用戶不需要知道內(nèi)部的具體構(gòu)建細(xì)節(jié)。

2、四個角色

1)Product(產(chǎn)品角色):一個具體的產(chǎn)品對象。

2)Builder(抽象建造者):創(chuàng)建一個 Product 對象的各個部件指定的 接口/抽象類。

3)ConcreteBuilder(具體建造者):實(shí)現(xiàn)接口,構(gòu)建和裝配各個部件。

4)Director(指揮者):構(gòu)建一個使用 Builder 接口的對象。它主要是用于創(chuàng)建一個復(fù)雜的對象。它主要有兩個作用,一是隔離了客戶與對象的生產(chǎn)過程,二是負(fù)責(zé)控制產(chǎn)品對象的生產(chǎn)過程。

在這里插入圖片描述

3、案例

建房子需要打樁、砌墻、封頂?shù)?#xff0c;不管普通房、別墅都需要這個過程。

在這里插入圖片描述

1、House類

//產(chǎn)品->Product
public class House {private String baise;private String wall;private String roofed;public String getBaise() {return baise;}public void setBaise(String baise) {this.baise = baise;}public String getWall() {return wall;}public void setWall(String wall) {this.wall = wall;}public String getRoofed() {return roofed;}public void setRoofed(String roofed) {this.roofed = roofed;}}

2、HouseBuilder抽象類

// 抽象的建造者
public abstract class HouseBuilder {protected House house = new House();//將建造的流程寫好, 抽象的方法public abstract void buildBasic();public abstract void buildWalls();public abstract void roofed();//建造房子好, 將產(chǎn)品(房子) 返回public House buildHouse() {return house;}}

3、CommonHouse類

public class CommonHouse extends HouseBuilder {@Overridepublic void buildBasic() {// TODO Auto-generated method stubSystem.out.println(" 普通房子打地基5米 ");}@Overridepublic void buildWalls() {// TODO Auto-generated method stubSystem.out.println(" 普通房子砌墻10cm ");}@Overridepublic void roofed() {// TODO Auto-generated method stubSystem.out.println(" 普通房子屋頂 ");}}

4、HighBuilding

public class HighBuilding extends HouseBuilder {@Overridepublic void buildBasic() {// TODO Auto-generated method stubSystem.out.println(" 高樓的打地基100米 ");}@Overridepublic void buildWalls() {// TODO Auto-generated method stubSystem.out.println(" 高樓的砌墻20cm ");}@Overridepublic void roofed() {// TODO Auto-generated method stubSystem.out.println(" 高樓的透明屋頂 ");}}

5、HouseDirector 類

public class HouseDirector {HouseBuilder houseBuilder = null;//構(gòu)造器傳入 houseBuilderpublic HouseDirector(HouseBuilder houseBuilder) {this.houseBuilder = houseBuilder;}//通過setter 傳入 houseBuilderpublic void setHouseBuilder(HouseBuilder houseBuilder) {this.houseBuilder = houseBuilder;}//如何處理建造房子的流程,交給指揮者public House constructHouse() {houseBuilder.buildBasic();houseBuilder.buildWalls();houseBuilder.roofed();return houseBuilder.buildHouse();}}

7、測試

public static void main(String[] args) {//蓋普通房子CommonHouse commonHouse = new CommonHouse();//準(zhǔn)備創(chuàng)建房子的指揮者HouseDirector houseDirector = new HouseDirector(commonHouse);//完成蓋房子,返回產(chǎn)品(普通房子)House house = houseDirector.constructHouse();System.out.println("--------------------------");//蓋高樓HighBuilding highBuilding = new HighBuilding();//重置建造者h(yuǎn)ouseDirector.setHouseBuilder(highBuilding);//完成蓋房子,返回產(chǎn)品(高樓)houseDirector.constructHouse();}

輸出:

普通房子打地基5米
普通房子砌墻10cm
普通房子屋頂


高樓的打地基100米
高樓的砌墻20cm
高樓的透明屋頂

4、總結(jié)

1)客戶端(使用程序)不必知道產(chǎn)品內(nèi)部組成的細(xì)節(jié),將產(chǎn)品本身與產(chǎn)品的創(chuàng)建過程解耦,使得相同的創(chuàng)建過程可以創(chuàng)建不同的產(chǎn)品對象
2)每一個具體建造者都相對獨(dú)立,而與其他的具體建造者無關(guān),因此可以很方便地替換具體建造者或增加新的具體建造者,用戶使用不同的具體建造者即可得到不同的產(chǎn)品對象

3)可以更加精細(xì)地控制產(chǎn)品的創(chuàng)建過程 。將復(fù)雜產(chǎn)品的創(chuàng)建步驟分解在不同的方法中,使得創(chuàng)建過程更加清晰,
也更方便使用程序來控制創(chuàng)建過程

4)增加新的具體建造者無須修改原有類庫的代碼,指揮者類針對抽象建造者類編程,系統(tǒng)擴(kuò)展方便,符合“開閉原則”

5)建造者模式所創(chuàng)建的產(chǎn)品一般具有較多的共同點(diǎn),其組成部分相似,如果產(chǎn)品之間的差異性很大,則不適合使用建造者模式,因此其使用范圍受到一定的限制。

6)如果產(chǎn)品的內(nèi)部變化復(fù)雜,可能會導(dǎo)致需要定義很多具體建造者類來實(shí)現(xiàn)這種變化,導(dǎo)致系統(tǒng)變得很龐大,因此在這種情況下,要考慮是否選擇建造者模式。

7)抽象工廠模式 VS 建造者模式
抽象工廠模式實(shí)現(xiàn)對產(chǎn)品家族的創(chuàng)建,一個產(chǎn)品家族是這樣的一系列產(chǎn)品:具有不同分類維度的產(chǎn)品組合,采用抽象工廠模式不需要關(guān)心構(gòu)建過程,只關(guān)心什么產(chǎn)品由什么工廠生產(chǎn)即可。而建造者模式則是要求按照指定的藍(lán)圖建造產(chǎn)品,它的主要目的是通過組裝零配件而產(chǎn)生一個新產(chǎn)品。

七、適配器模式

1、介紹

1)適配器模式(Adapter Pattern)將某個類的接口轉(zhuǎn)換成客戶端期望的另一個接口表示,主的目的是兼容性,讓原本因接口不匹配不能一起工作的兩個類可以協(xié)同工作。其別名為包裝器(Wrapper)

2)適配器模式屬于結(jié)構(gòu)型模式

3)主要分為三類:類適配器模式、對象適配器模式、接口適配器模式

2、類適配器模式

(1)介紹

? Adapter 類,通過繼承 src 類,實(shí)現(xiàn) dst 類接口,完成 src->dst 的適配

(2)案例

以生活中充電器的例子來講解適配器,充電器本身相當(dāng)于 Adapter,220V 交流電相當(dāng)于 src (即被適配者),目的dst(即 目標(biāo))是 5V 直流電

在這里插入圖片描述

1、適配器接口

//適配接口
public interface IVoltage5V {public int output5V();
}

2、被適配的類

//被適配的類
public class Voltage220V {//輸出220V的電壓,不變public int output220V() {int src = 220;System.out.println("電壓=" + src + "伏");return src;}
}

3、適配器類

//適配器類
public class VoltageAdapter extends Voltage220V implements IVoltage5V {@Overridepublic int output5V() {int srcV = output220V();//獲取220V 電壓int dst = srcV / 44; //轉(zhuǎn)成 5vreturn dst;}}

4、使用者

public class Phone {//充電public void charging(IVoltage5V iVoltage5V) {if(iVoltage5V.output5V() == 5) {System.out.println("電壓為5V, 可以充電~~");} else if (iVoltage5V.output5V() > 5) {System.out.println("電壓大于5V, 不能充電~~");}}
}

5、測試

    public static void main(String[] args) {Phone phone = new Phone();phone.charging(new VoltageAdapter());}

電壓=220伏
電壓為5V, 可以充電~~

(3)總結(jié)

1)Java 是單繼承機(jī)制,所以類適配器需要繼承 src 類這一點(diǎn)算是一個缺點(diǎn),因?yàn)檫@要求 dst 必須是接口,有一定局限性;

2)src 類的方法在 Adapter 中都會暴露出來,也增加了使用的成本。

3)由于其繼承了 src 類,所以它可以根據(jù)需求重寫 src 類的方法,使得 Adapter 的靈活性增強(qiáng)了。

3、對象適配器模式

(1)介紹

1)基本思路和類的適配器模式相同,只是將 Adapter 類作修改,不是繼承 src 類,而是持有 src 類的實(shí)例,以解決兼容性的問題。 即:持有 src類,實(shí)現(xiàn) dst 類接口,完成 src->dst 的適配

2)根據(jù)“合成復(fù)用原則”,在系統(tǒng)中盡量使用關(guān)聯(lián)關(guān)系(聚合)來替代繼承關(guān)系。

3)對象適配器模式是適配器模式常用的一種

在這里插入圖片描述

(2)案例

3、修改類適配器第三步改為對象適配

//適配器類
public class VoltageAdapter implements IVoltage5V {private Voltage220V voltage220V; // 關(guān)聯(lián)關(guān)系-聚合//通過構(gòu)造器,傳入一個 Voltage220V 實(shí)例public VoltageAdapter(Voltage220V voltage220v) {this.voltage220V = voltage220v;}@Overridepublic int output5V() {int dst = 0;if(null != voltage220V) {int src = voltage220V.output220V();//獲取220V 電壓System.out.println("使用對象適配器,進(jìn)行適配~~");dst = src / 44;System.out.println("適配完成,輸出的電壓為=" + dst);}return dst;}}

測試

    public static void main(String[] args) {Phone phone = new Phone();phone.charging(new VoltageAdapter(new Voltage220V()));}

電壓=220伏
使用對象適配器,進(jìn)行適配~~
適配完成,輸出的電壓為=5
電壓為5V, 可以充電~~

(3)總結(jié)

1)對象適配器和類適配器其實(shí)算是同一種思想,只不過實(shí)現(xiàn)方式不同。根據(jù)合成復(fù)用原則,使用組合替代繼承,所以它解決了類適配器必須繼承 src 的局限性問題,也不再要求 dst必須是接口。

2)使用成本更低,更靈活。

4、接口適配器模式

(1)介紹

1)核心思路:當(dāng)不需要全部實(shí)現(xiàn)接口提供的方法時,可先設(shè)計一個抽象類實(shí)現(xiàn)接口,并為該接口中每個方法提供一個默認(rèn)實(shí)現(xiàn)(空方法),那么該抽象類的子類可有選擇地覆蓋父類的某些方法來實(shí)現(xiàn)需求。

2)適用于一個接口不想使用其所有的方法的情況。

(2)案例

在這里插入圖片描述

1、接口

public interface Interface4 {public void m1();public void m2();public void m3();public void m4();
}

2、抽象類

//在AbsAdapter 我們將 Interface4 的方法進(jìn)行默認(rèn)實(shí)現(xiàn)
public abstract class AbsAdapter implements Interface4 {//默認(rèn)實(shí)現(xiàn)public void m1() {}public void m2() {}public void m3() {}public void m4() {}
}

3、測試

	public static void main(String[] args) {AbsAdapter absAdapter = new AbsAdapter() {//只需要去覆蓋我們 需要使用 接口方法@Overridepublic void m1() {System.out.println("使用了m1的方法");}};absAdapter.m1();}

使用了m1的方法

(3)總結(jié)

1)三種命名方式,是根據(jù) src 是以怎樣的形式給到 Adapter(在 Adapter 里的形式)來命名的。

2)類適配器:以類給到,在 Adapter 里,就是將 src當(dāng)做類,繼承

? 對象適配器:以對象給到,在 Adapter里,將src 作為一個對象,持有

? 接口適配器:以接口給到,在Adapter 里,將src 作為一個接口,實(shí)現(xiàn)

3)Adapter 模式最大的作用還是將原本不兼容的接口融合在一起工作。

八、橋接模式

1、介紹

1)橋接模式(Bridge 模式)是指:將實(shí)現(xiàn)與抽象放在兩個不同的類層次中,使兩個層次可以獨(dú)立改變。是一種結(jié)構(gòu)型設(shè)計模式。

2)Bridge 模式基于類的最小設(shè)計原則,通過使用封裝、聚合及繼承等行為讓不同的類承擔(dān)不同的職責(zé)。它的主要特點(diǎn)是把抽象(Abstaction)與行為實(shí)現(xiàn)(Implementation)分離開來,從而可以保持各部分的獨(dú)立性以及應(yīng)對他們的功能擴(kuò)展。

2、原理說明

在這里插入圖片描述

說明:

1)Client類:橋接模式的調(diào)用者

2)抽象類(Abstraction):維護(hù)了 Implementor/即它的實(shí)現(xiàn)類 ConcretelmplementorA…
二者是聚合關(guān)系,Abstraction充當(dāng)橋接類

3)RefinedAbstraction:是 Abstraction 抽象類的子類

4)Implementor:行為實(shí)現(xiàn)類的接口

5)ConcretelmplementorA/B :行為的具體實(shí)現(xiàn)類

6)從 UM 圖:這里的抽象類和接口是聚合的關(guān)系,其實(shí)調(diào)用和被調(diào)用關(guān)系

3、案例

手機(jī)打電話

在這里插入圖片描述

傳統(tǒng)類圖:

在這里插入圖片描述

? 擴(kuò)展性問題(類爆炸),如果我們再增加手機(jī)的樣式(旋轉(zhuǎn)式),就需要增加各個品牌手機(jī)的類,同樣如果我們增加一個手機(jī)品牌,也要在各個手機(jī)樣式類下增加。違反了單一職責(zé)原則,這樣增加了代碼維護(hù)成本

改進(jìn)類圖:

在這里插入圖片描述

1、接口Brand

//接口
public interface Brand {void open();void close();void call();
}

2、vivo手機(jī)

public class Vivo implements Brand {@Overridepublic void open() {System.out.println(" Vivo手機(jī)開機(jī) ");}@Overridepublic void close() {System.out.println(" Vivo手機(jī)關(guān)機(jī) ");}@Overridepublic void call() {System.out.println(" Vivo手機(jī)打電話 ");}}

3、小米手機(jī)

public class XiaoMi implements Brand {@Overridepublic void open() {System.out.println(" 小米手機(jī)開機(jī) ");}@Overridepublic void close() {System.out.println(" 小米手機(jī)關(guān)機(jī) ");}@Overridepublic void call() {System.out.println(" 小米手機(jī)打電話 ");}}

4、手機(jī)抽象類

public abstract class Phone {//組合品牌private Brand brand;//構(gòu)造器public Phone(Brand brand) {super();this.brand = brand;}protected void open() {brand.open();}protected void close() {brand.close();}protected void call() {brand.call();}}

5、折疊手機(jī)

//折疊式手機(jī)類,繼承 抽象類 Phone
public class FoldedPhone extends Phone {//構(gòu)造器public FoldedPhone(Brand brand) {super(brand);}public void open() {super.open();System.out.println(" 折疊樣式手機(jī) ");}public void close() {super.close();System.out.println(" 折疊樣式手機(jī) ");}public void call() {super.call();System.out.println(" 折疊樣式手機(jī) ");}
}

6、直立手機(jī)

public class UpRightPhone extends Phone {//構(gòu)造器public UpRightPhone(Brand brand) {super(brand);}public void open() {super.open();System.out.println(" 直立樣式手機(jī) ");}public void close() {super.close();System.out.println(" 直立樣式手機(jī) ");}public void call() {super.call();System.out.println(" 直立樣式手機(jī) ");}
}

7、測試

	public static void main(String[] args) {//獲取折疊式手機(jī) (樣式 + 品牌 )Phone phone1 = new FoldedPhone(new XiaoMi());phone1.open();phone1.call();phone1.close();System.out.println("=======================");Phone phone2 = new FoldedPhone(new Vivo());phone2.open();phone2.call();phone2.close();}

小米手機(jī)開機(jī)
折疊樣式手機(jī)
小米手機(jī)打電話
折疊樣式手機(jī)
小米手機(jī)關(guān)機(jī)
折疊樣式手機(jī)

Vivo手機(jī)開機(jī)
折疊樣式手機(jī)
Vivo手機(jī)打電話
折疊樣式手機(jī)
Vivo手機(jī)關(guān)機(jī)
折疊樣式手機(jī)

4、總結(jié)

1)實(shí)現(xiàn)了抽象和實(shí)現(xiàn)部分的分離,從而極大的提供了系統(tǒng)的靈活性,讓抽象部分和實(shí)現(xiàn)部分獨(dú)立開來,這有助于系統(tǒng)進(jìn)行分層設(shè)計,從而產(chǎn)生更好的結(jié)構(gòu)化系統(tǒng)。

2)對于系統(tǒng)的高層部分,只需要知道抽象部分和實(shí)現(xiàn)部分的接口就可以了,其它的部分由具體業(yè)務(wù)來完成。

3)橋接模式替代多層繼承方案,可以減少子類的個數(shù),降低系統(tǒng)的管理和維護(hù)成本。

4)橋接模式的引入增加了系統(tǒng)的理解和設(shè)計難度,由于聚合關(guān)聯(lián)關(guān)系建立在抽象層,要求開發(fā)者針對抽象進(jìn)行設(shè)
計和編程

5)橋接模式要求正確識別出系統(tǒng)中兩個獨(dú)立變化的維度(抽象、和實(shí)現(xiàn)),因此其使用范圍有一定的局限性,。

6)應(yīng)用場景

  • JDBC 驅(qū)動程序
  • 銀行轉(zhuǎn)賬系統(tǒng)
    • 轉(zhuǎn)賬分類:網(wǎng)上轉(zhuǎn)賬,柜臺轉(zhuǎn)賬,AMT轉(zhuǎn)賬
    • 轉(zhuǎn)賬用戶類型:普通用戶,銀卡用戶,金卡用戶
  • 消息管理
    • 消息類型:即時消息,延時消息
    • 消息分類:手機(jī)短信,郵件消息,QQ消息

九、裝飾者模式

1、介紹

裝飾者模式:動態(tài)的將新功能附加到對象上。在對象功能擴(kuò)展方面,它比繼承更有彈性,裝飾者模式也體現(xiàn)了開閉原則(ocp)

2、案例

1)咖啡種類/單品咖啡:Espresso(意大利濃咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(無因咖啡)

2)調(diào)料:Milk、Soy(豆?jié){)、Chocolate

3)要求在擴(kuò)展新的咖啡種類時,具有良好的擴(kuò)展性、改動方便、維護(hù)方便

4)使用 OO 來計算不同種類咖啡的費(fèi)用:客戶可以點(diǎn)單品咖啡,也可以單品咖啡+調(diào)料組合。

傳統(tǒng)類圖:

在這里插入圖片描述

1)可以控制類的數(shù)量,不至于造成很多的類

2)在增加或者刪除調(diào)料種類時,代碼的維護(hù)量很大

3)考慮到用戶可以添加多份 調(diào)料時,可以將 hasMilk 返回一個對應(yīng) int

改進(jìn)類圖

在這里插入圖片描述

1、drink抽象類

public abstract class Drink {public String des; // 描述private float price = 0.0f;public String getDes() {return des;}public void setDes(String des) {this.des = des;}public float getPrice() {return price;}public void setPrice(float price) {this.price = price;}//計算費(fèi)用的抽象方法//子類來實(shí)現(xiàn)public abstract float cost();}

2、coffee類

public class Coffee  extends Drink {@Overridepublic float cost() {return super.getPrice();}}

3、濃縮咖啡

public class ShortBlack extends Coffee{public ShortBlack() {setDes(" shortblack ");setPrice(4.0f);}
}

4、無因咖啡

public class DeCaf extends Coffee {public DeCaf() {setDes(" 無因咖啡 ");setPrice(1.0f);}
}

5、意大利咖啡

public class Espresso extends Coffee {public Espresso() {setDes(" 意大利咖啡 ");setPrice(6.0f);}
}

6、美式咖啡

public class LongBlack extends Coffee {public LongBlack() {setDes(" longblack ");setPrice(5.0f);}
}

以上都是咖啡類型

7、裝飾類

public class Decorator extends Drink {private Drink obj;public Decorator(Drink obj) { //組合this.obj = obj;}@Overridepublic float cost() {// getPrice 自己價格return super.getPrice() + obj.cost();}@Overridepublic String getDes() {// obj.getDes() 輸出被裝飾者的信息return des + " " + getPrice() + " && " + obj.getDes();}}

8、巧克力

//具體的Decorator, 這里就是調(diào)味品
public class Chocolate extends Decorator {public Chocolate(Drink obj) {super(obj);setDes(" 巧克力 ");setPrice(3.0f); // 調(diào)味品 的價格}}

9、牛奶

public class Milk extends Decorator {public Milk(Drink obj) {super(obj);setDes(" 牛奶 ");setPrice(2.0f); }}

10、豆?jié){

public class Soy extends Decorator{public Soy(Drink obj) {super(obj);setDes(" 豆?jié){  ");setPrice(1.5f);}}

11、測試

	public static void main(String[] args) {// 裝飾者模式下的訂單:2份巧克力+一份牛奶的LongBlack// 1. 點(diǎn)一份 LongBlackDrink order = new LongBlack();System.out.println("費(fèi)用1=" + order.cost());System.out.println("描述=" + order.getDes());// 2. order 加入一份牛奶order = new Milk(order);System.out.println("order 加入一份牛奶 費(fèi)用 =" + order.cost());System.out.println("order 加入一份牛奶 描述 = " + order.getDes());// 3. order 加入一份巧克力order = new Chocolate(order);System.out.println("order 加入一份牛奶 加入一份巧克力  費(fèi)用 =" + order.cost());System.out.println("order 加入一份牛奶 加入一份巧克力 描述 = " + order.getDes());// 3. order 加入一份巧克力order = new Chocolate(order);System.out.println("order 加入一份牛奶 加入2份巧克力   費(fèi)用 =" + order.cost());System.out.println("order 加入一份牛奶 加入2份巧克力 描述 = " + order.getDes());System.out.println("===========================");Drink order2 = new DeCaf();System.out.println("order2 無因咖啡  費(fèi)用 =" + order2.cost());System.out.println("order2 無因咖啡 描述 = " + order2.getDes());order2 = new Milk(order2);
x		System.out.println("order2 無因咖啡 加入一份牛奶  費(fèi)用 =" + order2.cost());System.out.println("order2 無因咖啡 加入一份牛奶 描述 = " + order2.getDes());}

描述= longblack
order 加入一份牛奶 費(fèi)用 =7.0
order 加入一份牛奶 描述 = 牛奶 2.0 && longblack
order 加入一份牛奶 加入一份巧克力 費(fèi)用 =10.0
order 加入一份牛奶 加入一份巧克力 描述 = 巧克力 3.0 && 牛奶 2.0 && longblack
order 加入一份牛奶 加入2份巧克力 費(fèi)用 =13.0
order 加入一份牛奶 加入2份巧克力 描述 = 巧克力 3.0 && 巧克力 3.0 && 牛奶 2.0 && longblack

=============================================

order2 無因咖啡 費(fèi)用 =1.0
order2 無因咖啡 描述 = 無因咖啡
order2 無因咖啡 加入一份牛奶 費(fèi)用 =3.0
order2 無因咖啡 加入一份牛奶 描述 = 牛奶 2.0 && 無因咖啡

3、jdk中的使用

Java 的 IO 結(jié)構(gòu),FilterInputStream 就是一個裝飾者

在這里插入圖片描述

public static void main(Stringl args) throws Exception{//說明//1.nputStream 是抽象類,類似我們前面講的 Drink//2. FilelnputStream 是InputStream 子類,類似我們前面的 DeCaf, LongBlack//3.FilterlnputStream 是 InputStream 子類:類似我們前面 的 Decorator 修飾者//4. DatalnputStream 是 FilterlnputStream 子類,具體的修飾者,類似前面的 Mik, Soy 等//5.FilterInputStream 類有protected volatile InputStream in;即含被裝飾者//6.分析得出在 jdk 的io體系中,就是使用裝飾者模式DatalnputStream dis = new DatalnputStream(new FileInputStream("d:\\abc.txt" ))System.out.println(dis.read());dis.close();
}

十、組合模式

1、介紹

1)組合模式(Composite Pattern),又叫部分整體模式,它創(chuàng)建了對象組的樹形結(jié)構(gòu),將對象組合成樹狀結(jié)構(gòu)以表示**“整體-部分”**的層次關(guān)系。

2)組合模式依據(jù)樹形結(jié)構(gòu)來組合對象,用來表示部分以及整體層次。

3)組合模式使得用戶對單個對象和組合對象的訪問具有一致性,即:組合能讓客戶以一致的方式處理個別對象以
及組合對象

2、原理

在這里插入圖片描述

1)Component:這是組合中對象聲明接口,在適當(dāng)情況下,實(shí)現(xiàn)所有類共有的接口默認(rèn)行為,用于訪問和管理Component 子部件,Component 可以是抽象類或者接口

2)Leaf:在組合中表示葉子節(jié)點(diǎn),葉子節(jié)點(diǎn)沒有子節(jié)點(diǎn)

3)Composite:非葉子節(jié)點(diǎn), 用于存儲子部件, 在 Component 接口中實(shí)現(xiàn) 子部件的相關(guān)操作,比如增加(add),刪除。

3、案例

編寫程序展示一個學(xué)校院系結(jié)構(gòu):要在一個頁面中展示出學(xué)校的院系組成,一個學(xué)校有多個學(xué)院,個學(xué)院有多個系。

在這里插入圖片描述

1、抽象類

public abstract class OrganizationComponent {private String name; // 名字private String des; // 說明protected  void add(OrganizationComponent organizationComponent) {//默認(rèn)實(shí)現(xiàn)throw new UnsupportedOperationException();}protected  void remove(OrganizationComponent organizationComponent) {//默認(rèn)實(shí)現(xiàn)throw new UnsupportedOperationException();}//構(gòu)造器public OrganizationComponent(String name, String des) {super();this.name = name;this.des = des;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getDes() {return des;}public void setDes(String des) {this.des = des;}//方法print, 做成抽象的, 子類都需要實(shí)現(xiàn)protected abstract void print();}

2、學(xué)校

//University 就是 Composite , 可以管理College
public class University extends OrganizationComponent {List<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>();// 構(gòu)造器public University(String name, String des) {super(name, des);}// 重寫add@Overrideprotected void add(OrganizationComponent organizationComponent) {organizationComponents.add(organizationComponent);}// 重寫remove@Overrideprotected void remove(OrganizationComponent organizationComponent) {organizationComponents.remove(organizationComponent);}@Overridepublic String getName() {return super.getName();}@Overridepublic String getDes() {return super.getDes();}// print方法,就是輸出University 包含的學(xué)院@Overrideprotected void print() {System.out.println("--------------" + getName() + "--------------");//遍歷 organizationComponents for (OrganizationComponent organizationComponent : organizationComponents) {organizationComponent.print();}}}

3、學(xué)院

public class College extends OrganizationComponent {//List 中 存放的DepartmentList<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>();// 構(gòu)造器public College(String name, String des) {super(name, des);}// 重寫add@Overrideprotected void add(OrganizationComponent organizationComponent) {//  將來實(shí)際業(yè)務(wù)中,Colleage 的 add 和  University add 不一定完全一樣organizationComponents.add(organizationComponent);}// 重寫remove@Overrideprotected void remove(OrganizationComponent organizationComponent) {organizationComponents.remove(organizationComponent);}@Overridepublic String getName() {return super.getName();}@Overridepublic String getDes() {return super.getDes();}// print方法,就是輸出University 包含的學(xué)院@Overrideprotected void print() {System.out.println("--------------" + getName() + "--------------");//遍歷 organizationComponents for (OrganizationComponent organizationComponent : organizationComponents) {organizationComponent.print();}}}

4、院系

public class Department extends OrganizationComponent {//沒有集合public Department(String name, String des) {super(name, des);}//add , remove 就不用寫了,因?yàn)樗侨~子節(jié)點(diǎn)@Overridepublic String getName() {return super.getName();}@Overridepublic String getDes() {return super.getDes();}@Overrideprotected void print() {System.out.println(getName());}}

5、測試

public static void main(String[] args) {//從大到小創(chuàng)建對象 學(xué)校OrganizationComponent university = new University("清華大學(xué)", " 中國頂級大學(xué) ");//創(chuàng)建 學(xué)院OrganizationComponent computerCollege = new College("計算機(jī)學(xué)院", " 計算機(jī)學(xué)院 ");OrganizationComponent infoEngineercollege = new College("信息工程學(xué)院", " 信息工程學(xué)院 ");//創(chuàng)建各個學(xué)院下面的系(專業(yè))computerCollege.add(new Department("軟件工程", " 軟件工程不錯 "));computerCollege.add(new Department("網(wǎng)絡(luò)工程", " 網(wǎng)絡(luò)工程不錯 "));computerCollege.add(new Department("計算機(jī)科學(xué)與技術(shù)", " 計算機(jī)科學(xué)與技術(shù)是老牌的專業(yè) "));infoEngineercollege.add(new Department("通信工程", " 通信工程不好學(xué) "));infoEngineercollege.add(new Department("信息工程", " 信息工程好學(xué) "));//將學(xué)院加入到 學(xué)校university.add(computerCollege);university.add(infoEngineercollege);university.print();
//		infoEngineercollege.print();}

--------------清華大學(xué)--------------
--------------計算機(jī)學(xué)院--------------
軟件工程
網(wǎng)絡(luò)工程
計算機(jī)科學(xué)與技術(shù)
--------------信息工程學(xué)院--------------
通信工程
信息工程

4、總結(jié)

1)簡化客戶端操作??蛻舳酥恍枰鎸σ恢碌膶ο蠖挥每紤]整體部分或者節(jié)點(diǎn)葉子的問題。

2)具有較強(qiáng)的擴(kuò)展性。當(dāng)要更改組合對象時,我們只需要調(diào)整內(nèi)部的層次關(guān)系,客戶端不用做出任何改動.

3)方便創(chuàng)建出復(fù)雜的層次結(jié)構(gòu)??蛻舳瞬挥美頃M合里面的組成細(xì)節(jié),容易添加節(jié)點(diǎn)或者葉子從而創(chuàng)建出復(fù)雜的樹形結(jié)構(gòu)

4)需要遍歷組織機(jī)構(gòu),或者處理的對象具有樹形結(jié)構(gòu)時,非常適合使用組合模式

5)要求較高的抽象性,如果節(jié)點(diǎn)和葉子有很多差異性的話,比如很多方法和屬性都不一樣,不適合使用組合模式

十一、外觀模式

1、介紹

1)外觀模式(Facade),也叫“過程模式:外觀模式為子系統(tǒng)中的一組接口提供一個一致的界面,此模式定義了一個高層接口,這個接口使得這一子系統(tǒng)更加容易使用

2)外觀模式通過定義一個一致的接口,用以屏蔽內(nèi)部子系統(tǒng)的細(xì)節(jié),使得調(diào)用端只需跟這個接口發(fā)生調(diào)用,而無需關(guān)心這個子系統(tǒng)的內(nèi)部細(xì)節(jié)

2、案例

組建一個家庭影院:
DVD 播放器、投影儀、自動屏幕、環(huán)繞立體聲、爆米花機(jī),要求完成使用家庭影院的功能,其過程為:直接用遙控器:統(tǒng)籌各設(shè)備開關(guān)
開爆米花機(jī)
放下屏幕
開投影儀
開音響
開 DVD,選 dvd
去拿爆米花
調(diào)暗燈光
播放
觀影結(jié)束后,關(guān)閉各種設(shè)備

在這里插入圖片描述

1、爆米花類

public class Popcorn {private static Popcorn instance = new Popcorn();public static Popcorn getInstance() {return instance;}public void on() {System.out.println(" popcorn on ");}public void off() {System.out.println(" popcorn ff ");}public void pop() {System.out.println(" popcorn is poping  ");}
}

2、屏幕類

public class Screen {private static Screen instance = new Screen();public static Screen getInstance() {return instance;}public void up() {System.out.println(" Screen up ");}public void down() {System.out.println(" Screen down ");}}

3、投影儀類

public class Projector {private static Projector instance = new Projector();public static Projector getInstance() {return instance;}public void on() {System.out.println(" Projector on ");}public void off() {System.out.println(" Projector ff ");}public void focus() {System.out.println(" Projector is Projector  ");}}

4、音響類

public class Stereo {private static Stereo instance = new Stereo();public static Stereo getInstance() {return instance;}public void on() {System.out.println(" Stereo on ");}public void off() {System.out.println(" Screen off ");}public void up() {System.out.println(" Screen up.. ");}}

5、dvd類

public class DVDPlayer {//使用單例模式, 使用餓漢式private static DVDPlayer instance = new DVDPlayer();public static DVDPlayer getInstanc() {return instance;}public void on() {System.out.println(" dvd on ");}public void off() {System.out.println(" dvd off ");}public void play() {System.out.println(" dvd is playing ");}public void pause() {System.out.println(" dvd pause ..");}
}

6、燈光類

public class TheaterLight {private static TheaterLight instance = new TheaterLight();public static TheaterLight getInstance() {return instance;}public void on() {System.out.println(" TheaterLight on ");}public void off() {System.out.println(" TheaterLight off ");}public void dim() {System.out.println(" TheaterLight dim.. ");}public void bright() {System.out.println(" TheaterLight bright.. ");}
}

7、統(tǒng)籌類(家庭影院)

public class HomeTheaterFacade {//定義各個子系統(tǒng)對象private TheaterLight theaterLight;private Popcorn popcorn;private Stereo stereo;private Projector projector;private Screen screen;private DVDPlayer dVDPlayer;//構(gòu)造器public HomeTheaterFacade() {super();this.theaterLight = TheaterLight.getInstance();this.popcorn = Popcorn.getInstance();this.stereo = Stereo.getInstance();this.projector = Projector.getInstance();this.screen = Screen.getInstance();this.dVDPlayer = DVDPlayer.getInstanc();}//操作分成 4 步public void ready() {popcorn.on();popcorn.pop();screen.down();projector.on();stereo.on();dVDPlayer.on();theaterLight.dim();}public void play() {dVDPlayer.play();}public void pause() {dVDPlayer.pause();}public void end() {popcorn.off();theaterLight.bright();screen.up();projector.off();stereo.off();dVDPlayer.off();}}

8、測試

	public static void main(String[] args) {//這里直接調(diào)用。。 很麻煩HomeTheaterFacade homeTheaterFacade = new HomeTheaterFacade();// 開始System.out.println("==============開始播放=============");homeTheaterFacade.ready();// 暫停System.out.println("==============暫停=============");homeTheaterFacade.play();// 結(jié)束System.out.println("==============結(jié)束=============");homeTheaterFacade.end();

==開始播放=
popcorn on
popcorn is poping
Screen down
Projector on
Stereo on
dvd on
TheaterLight dim…
==暫停=
dvd is playing
==結(jié)束=
popcorn ff
TheaterLight bright…
Screen up
Projector ff
Screen off
dvd off

3、總結(jié)

1)外觀模式對外屏蔽了子系統(tǒng)的細(xì)節(jié),因此外觀模式降低了客戶端對子系統(tǒng)使用的復(fù)雜性

2)外觀模式對客戶端與子系統(tǒng)的耦合關(guān)系-解耦,讓子系統(tǒng)內(nèi)部的模塊更易維護(hù)和擴(kuò)展

3)通過合理的使用外觀模式,可以幫我們更好的劃分訪問的層次

4)當(dāng)系統(tǒng)需要進(jìn)行分層設(shè)計時,可以考慮使用Facade 模式

5)在維護(hù)一個遺留的大型系統(tǒng)時,可能這個系統(tǒng)已經(jīng)變得非常難以維護(hù)和擴(kuò)展,此時可以考慮為新系統(tǒng)開發(fā)一個Facade 類,來提供遺留系統(tǒng)的比較清晰簡單的接口,讓新系統(tǒng)與 Facade 類交互,提高復(fù)用性

十二、享元模式

1、介紹

1)享元模式(Flyweight Pattern) 也叫 蠅量模式:運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度的對象

2)常用于系統(tǒng)底層開發(fā),解決系統(tǒng)的性能問題。像數(shù)據(jù)庫連接池,里面都是創(chuàng)建好的連接對象,在這些連接對象中有我們需要的則直接拿來用,避免重新創(chuàng)建,如果沒有我們需要的,則創(chuàng)建一個

3)享元模式能夠解決重復(fù)對象的內(nèi)存浪費(fèi)的問題,當(dāng)系統(tǒng)中有大量相似對象,需要緩沖池時。不需總是創(chuàng)建新對象,可以從緩沖池里拿。這樣可以降低系統(tǒng)內(nèi)存,同時提高效率

4)享元模式經(jīng)典的應(yīng)用場景就是池技術(shù)了,String 常量池、數(shù)據(jù)庫連接池、緩沖池等等都是享元模式的應(yīng)用,享
元模式是池技術(shù)的重要實(shí)現(xiàn)方式

2、內(nèi)部狀態(tài)與外部狀態(tài)

1)享元模式提出了兩個要求:細(xì)粒度和共享對象。即將對象的信息分為兩個部分:內(nèi)部狀態(tài)和外部狀態(tài)
2)內(nèi)部狀態(tài)指對象共享出來的信息,存儲在享元對象內(nèi)部且不會隨環(huán)境的改變而改變

3)外部狀態(tài)指對象得以依賴的一個標(biāo)記,是隨環(huán)境改變而改變的、不可共享的狀態(tài)。

3、案例

小型的外包項目,給客戶 A做一個產(chǎn)品展示網(wǎng)站,客戶A的朋友感覺效果不錯,也希望做這樣的產(chǎn)品展示網(wǎng)站,但是要求都有些不同:
1)有客戶要求以新聞的形式發(fā)布
2)有客戶人要求以博客的形式發(fā)布
3)有客戶希望以微信公眾號的形式發(fā)布

在這里插入圖片描述

1、外部狀態(tài)user

public class User {private String name;public User(String name) {super();this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}}

2、抽象類

public abstract class WebSite {public abstract void use(User user);//抽象方法
}

3、具體網(wǎng)站

//具體網(wǎng)站
public class ConcreteWebSite extends WebSite {//共享的部分,內(nèi)部狀態(tài)private String type = ""; //網(wǎng)站發(fā)布的形式(類型)//構(gòu)造器public ConcreteWebSite(String type) {this.type = type;}@Overridepublic void use(User user) {System.out.println("網(wǎng)站的發(fā)布形式為:" + type + " 在使用中 .. 使用者是" + user.getName());}}

4、工廠類

// 網(wǎng)站工廠類,根據(jù)需要返回壓一個網(wǎng)站
public class WebSiteFactory {//集合, 充當(dāng)池的作用private HashMap<String, ConcreteWebSite> pool = new HashMap<>();//根據(jù)網(wǎng)站的類型,返回一個網(wǎng)站, 如果沒有就創(chuàng)建一個網(wǎng)站,并放入到池中,并返回public WebSite getWebSiteCategory(String type) {if(!pool.containsKey(type)) {//就創(chuàng)建一個網(wǎng)站,并放入到池中pool.put(type, new ConcreteWebSite(type));}return (WebSite)pool.get(type);}//獲取網(wǎng)站分類的總數(shù) (池中有多少個網(wǎng)站類型)public int getWebSiteCount() {return pool.size();}
}

5、測試

public static void main(String[] args) {// 創(chuàng)建一個工廠類WebSiteFactory factory = new WebSiteFactory();// 客戶要一個以新聞形式發(fā)布的網(wǎng)站WebSite webSite1 = factory.getWebSiteCategory("新聞");webSite1.use(new User("tom"));// 客戶要一個以博客形式發(fā)布的網(wǎng)站WebSite webSite2 = factory.getWebSiteCategory("博客");webSite2.use(new User("jack"));// 客戶要一個以博客形式發(fā)布的網(wǎng)站WebSite webSite3 = factory.getWebSiteCategory("博客");webSite3.use(new User("smith"));// 客戶要一個以博客形式發(fā)布的網(wǎng)站WebSite webSite4 = factory.getWebSiteCategory("博客");webSite4.use(new User("king"));System.out.println("網(wǎng)站的分類共=" + factory.getWebSiteCount());}

網(wǎng)站的發(fā)布形式為:新聞 在使用中 … 使用者是tom
網(wǎng)站的發(fā)布形式為:博客 在使用中 … 使用者是jack
網(wǎng)站的發(fā)布形式為:博客 在使用中 … 使用者是smith
網(wǎng)站的發(fā)布形式為:博客 在使用中 … 使用者是king
網(wǎng)站的分類共=2

4、總結(jié)

1)享元模式理解:“享”就表示共享,“元”表示對象

2)系統(tǒng)中有大量對象,這些對象消耗大量內(nèi)存,并且對象的狀態(tài)大部分可以外部化時,我們就可以考慮選用享元模式

3)用唯一標(biāo)識碼判斷,如果在內(nèi)存中有,則返回這個唯一標(biāo)識碼所標(biāo)識的對象,用 HashMap/HashTable

4)存儲享元模式大大減少了對象的創(chuàng)建,降低了程序內(nèi)存的占用,提高效率

5)享元模式提高了系統(tǒng)的復(fù)雜度。需要分離出內(nèi)部狀態(tài)和外部狀態(tài),而外部狀態(tài)具有固化特性,不應(yīng)該隨著內(nèi)部狀態(tài)的改變而改變,這是我們使用享元模式需要注意的地方

6)使用享元模式時,注意劃分內(nèi)部狀態(tài)和外部狀態(tài),并且需要有一個工廠類加以控制。

7)享元模式經(jīng)典的應(yīng)用場景是需要緩沖池的場景,比如String 常量池、數(shù)據(jù)庫連接池

十三、代理模式

1、介紹

1)代理模式:為一個對象提供一個替身,以控制對這個對象的訪問。即通過代理對象訪問目標(biāo)對象,優(yōu)點(diǎn)是:可以在目標(biāo)對象實(shí)現(xiàn)的基礎(chǔ)上,增強(qiáng)額外的功能操作,即擴(kuò)展目標(biāo)對象的功能。

2)被代理的對象可以是遠(yuǎn)程對象、創(chuàng)建開銷大的對象或需要安全控制的對象

3)代理模式有不同的形式。主要有三種 靜態(tài)代理、動態(tài)代理(JDK 代理、接口代理)和 Cglib 代理(可以在內(nèi)存動態(tài)的創(chuàng)建對象,而不需要實(shí)現(xiàn)接口,屬于動態(tài)代理的范疇)。

2、靜態(tài)代理

(1)介紹

? 靜態(tài)代理在使用時,需要定義接口或者父類,被代理對象(即目標(biāo)對象)與代理對象一起實(shí)現(xiàn)相同的接口或者是繼承相同父類。

(2)案例

1)定義一個接口:ITeacherDao

2)目標(biāo)對象 TeacherDA0 實(shí)現(xiàn)接口 ITeacherDAO

3)使用靜態(tài)代理方式,就需要在代理對象 TeacherDAOProxy 中也實(shí)現(xiàn) ITeacherDAO

4)調(diào)用的時候通過調(diào)用代理對象的方法來調(diào)用目標(biāo)對象

5)代理對象與目標(biāo)對象要實(shí)現(xiàn)相同的接口,然后通過調(diào)用相同的方法來調(diào)用目標(biāo)對象的方法

在這里插入圖片描述

1、接口

//接口
public interface ITeacherDao {void teach(); // 授課的方法
}

2、目標(biāo)對象

public class TeacherDao implements ITeacherDao {@Overridepublic void teach() {System.out.println(" 老師授課中  。。。。。");}}

3、代理對象

//代理對象,靜態(tài)代理
public class TeacherDaoProxy implements ITeacherDao{private ITeacherDao target; // 目標(biāo)對象,通過接口來聚合//構(gòu)造器public TeacherDaoProxy(ITeacherDao target) {this.target = target;}@Overridepublic void teach() {System.out.println("開始代理  完成某些操作。。。。。 ");//方法target.teach();System.out.println("提交。。。。。");//方法}}

4、測試

	public static void main(String[] args) {// TODO Auto-generated method stub//創(chuàng)建目標(biāo)對象(被代理對象)TeacherDao teacherDao = new TeacherDao();//創(chuàng)建代理對象, 同時將被代理對象傳遞給代理對象TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);//通過代理對象,調(diào)用到被代理對象的方法//即:執(zhí)行的是代理對象的方法,代理對象再去調(diào)用目標(biāo)對象的方法 teacherDaoProxy.teach();}

開始代理 完成某些操作。。。。。
老師授課中 。。。。。
提交。。。。。

(3)總結(jié)

1)優(yōu)點(diǎn):在不修改目標(biāo)對象的功能前提下,能通過代理對象對目標(biāo)功能擴(kuò)展

2)缺點(diǎn):因?yàn)榇韺ο笮枰c目標(biāo)對象實(shí)現(xiàn)一樣的接口,所以會有很多代理類

3)一旦接口增加方法,目標(biāo)對象與代理對象都要維護(hù)

3、動態(tài)代理

(1)介紹

1)代理對象,不需要實(shí)現(xiàn)接口,但是目標(biāo)對象要實(shí)現(xiàn)接口,否則不能用動態(tài)代理

2)代理對象的生成,是利用JDK的API,動態(tài)的在內(nèi)存中構(gòu)建代理對象

3)動態(tài)代理也叫做:JDK 代理、接口代理

4)在jdk中生成代理對象api

  • 代理類所在包:java.lang.reflect.Proxy

  • JDK 實(shí)現(xiàn)代理只需要使用 newProxyInstance 方法,但是該方法需要接收三個參數(shù),寫法是:

    static Obiect newProxyInstance(ClassLoader loader. Class<?> interfaces.InvocationHandler h)

(2)案例

將靜態(tài)代理改為動態(tài)代理

在這里插入圖片描述

1、接口

//接口
public interface ITeacherDao {void teach(); // 授課方法void sayHello(String name);
}

2、目標(biāo)對象實(shí)現(xiàn)

public class TeacherDao implements ITeacherDao {@Overridepublic void teach() {System.out.println(" 老師授課中.... ");}@Overridepublic void sayHello(String name) {System.out.println("hello " + name);}}

3、代理

public class ProxyFactory {//維護(hù)一個目標(biāo)對象 , Objectprivate Object target;//構(gòu)造器 , 對target 進(jìn)行初始化public ProxyFactory(Object target) {this.target = target;} //給目標(biāo)對象 生成一個代理對象public Object getProxyInstance() {//說明/**  public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)//1. ClassLoader loader : 指定當(dāng)前目標(biāo)對象使用的類加載器, 獲取加載器的方法固定//2. Class<?>[] interfaces: 目標(biāo)對象實(shí)現(xiàn)的接口類型,使用泛型方法確認(rèn)類型//3. InvocationHandler h : 事情處理,執(zhí)行目標(biāo)對象的方法時,會觸發(fā)事情處理器方法, 會把當(dāng)前執(zhí)行的目標(biāo)對象方法作為參數(shù)傳入*/return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("JDK代理開始~~");//反射機(jī)制調(diào)用目標(biāo)對象的方法Object returnVal = method.invoke(target, args);System.out.println("JDK代理提交");return returnVal;}}); }}

4、測試

	public static void main(String[] args) {//創(chuàng)建目標(biāo)對象ITeacherDao target = new TeacherDao();//給目標(biāo)對象,創(chuàng)建代理對象, 可以轉(zhuǎn)成 ITeacherDaoITeacherDao proxyInstance = (ITeacherDao)new ProxyFactory(target).getProxyInstance();// proxyInstance=class com.sun.proxy.$Proxy0 內(nèi)存中動態(tài)生成了代理對象System.out.println("proxyInstance=" + proxyInstance.getClass());//通過代理對象,調(diào)用目標(biāo)對象的方法//proxyInstance.teach();proxyInstance.sayHello(" tom ");}

proxyInstance=class com.sun.proxy.$Proxy0
JDK代理開始~~
hello tom
JDK代理提交

4、Cglib代理

(1)介紹

1)靜態(tài)代理和JDK 代理模式都要求目標(biāo)對象是實(shí)現(xiàn)一個接口,但是有時候目標(biāo)對象只是一個單獨(dú)的對象,并沒有實(shí)現(xiàn)任何的接口,這個時候可使用目標(biāo)對象子類來實(shí)現(xiàn)代理-這就是 Cglib 代理

2)Cglib代理也叫作子類代理,它是在內(nèi)存中構(gòu)建一個子類對象從而實(shí)現(xiàn)對目標(biāo)對象功能擴(kuò)展,有些書也將Cglib代理歸屬到動態(tài)代理。

3)Cglib 是一個強(qiáng)大的高性能的代碼生成包,它可以在運(yùn)行期擴(kuò)展java類與實(shí)現(xiàn) java接口,它廣泛的被許多 AOP 的框架使用,例如 Spring AOP,實(shí)現(xiàn)方法攔截

4)在 AOP 編程中如何選擇代理模式:

  • 目標(biāo)對象需要實(shí)現(xiàn)接口,用 JDK 代理

  • 目標(biāo)對象不需要實(shí)現(xiàn)接口,用 Cglib 代理

5)Cglib 包的底層是通過使用字節(jié)碼處理框架 ASM 來轉(zhuǎn)換字節(jié)碼并生成新的類

(2)實(shí)現(xiàn)步驟

1)引入cglib的jar包

在這里插入圖片描述

2)在內(nèi)存中動態(tài)構(gòu)建子類,注意代理的類不能為fnal,否則報錯 java.lang.IllegalArgumentException:

3)目標(biāo)對象的方法如果為 final/static,那么就不會被攔截,即不會執(zhí)行目標(biāo)對象額外的業(yè)務(wù)方法

(3)案例

在這里插入圖片描述

1、目標(biāo)對象

public class TeacherDao {public String teach() {System.out.println(" 老師授課中  , 我是cglib代理,不需要實(shí)現(xiàn)接口 ");return "hello";}
}

2、代理類

public class ProxyFactory implements MethodInterceptor {//維護(hù)一個目標(biāo)對象private Object target;//構(gòu)造器,傳入一個被代理的對象public ProxyFactory(Object target) {this.target = target;}//返回一個代理對象:  是 target 對象的代理對象public Object getProxyInstance() {//1. 創(chuàng)建一個工具類Enhancer enhancer = new Enhancer();//2. 設(shè)置父類enhancer.setSuperclass(target.getClass());//3. 設(shè)置回調(diào)函數(shù)enhancer.setCallback(this);//4. 創(chuàng)建子類對象,即代理對象return enhancer.create();}//重寫  intercept 方法,會調(diào)用目標(biāo)對象的方法@Overridepublic Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {System.out.println("Cglib代理模式 ~~ 開始");Object returnVal = method.invoke(target, args);System.out.println("Cglib代理模式 ~~ 提交");return returnVal;}}

3、測試

public static void main(String[] args) {//創(chuàng)建目標(biāo)對象TeacherDao target = new TeacherDao();//獲取到代理對象,并且將目標(biāo)對象傳遞給代理對象TeacherDao proxyInstance = (TeacherDao)new ProxyFactory(target).getProxyInstance();//執(zhí)行代理對象的方法,觸發(fā)intecept 方法,從而實(shí)現(xiàn) 對目標(biāo)對象的調(diào)用String res = proxyInstance.teach();System.out.println("res=" + res);
}

Cglib代理模式 ~~ 開始
老師授課中 , 我是cglib代理,不需要實(shí)現(xiàn)接口
Cglib代理模式 ~~ 提交
res=hello

http://m.aloenet.com.cn/news/40737.html

相關(guān)文章:

  • 如何開發(fā)一個app建設(shè)一個網(wǎng)站關(guān)鍵詞搜索熱度查詢
  • 廣西搜索推廣東莞網(wǎng)絡(luò)優(yōu)化排名
  • 網(wǎng)站IcP在哪查今日剛剛發(fā)生的國際新聞
  • 哈爾濱網(wǎng)站建設(shè)1元錢2021年經(jīng)典營銷案例
  • 做企業(yè)網(wǎng)站的第一步需要啥紹興seo優(yōu)化
  • 四川seo整站優(yōu)化吧谷歌瀏覽器官方app下載
  • 國外做美食視頻網(wǎng)站谷歌海外推廣怎么做
  • 淄博網(wǎng)站建設(shè)推廣優(yōu)化自媒體賬號申請
  • 網(wǎng)站制作系統(tǒng)長沙官網(wǎng)seo技術(shù)廠家
  • 黃石規(guī)劃建設(shè)局網(wǎng)站一鍵優(yōu)化清理手機(jī)
  • 做一個網(wǎng)上商城網(wǎng)站建設(shè)費(fèi)用多少錢市場調(diào)研分析報告范文
  • 網(wǎng)站開發(fā)素材包網(wǎng)站的宣傳與推廣
  • 網(wǎng)站建設(shè)后臺管理怎么進(jìn)入烏魯木齊seo
  • 商城網(wǎng)站模版代碼重慶seo整站優(yōu)化方案范文
  • 開發(fā)動態(tài)網(wǎng)站有哪些技術(shù)百度人工客服電話24小時
  • 網(wǎng)站開發(fā)全包免費(fèi)手機(jī)優(yōu)化大師下載安裝
  • 外貿(mào)品牌網(wǎng)站設(shè)計公司鼓樓網(wǎng)頁seo搜索引擎優(yōu)化
  • 網(wǎng)站開發(fā)需求列表2021最火營銷方案
  • 怎么可以自己做網(wǎng)站被百度收到網(wǎng)站seo公司哪家好
  • 石家莊網(wǎng)站建設(shè)價格低廣州今日新聞頭條新聞
  • 表白網(wǎng)站怎樣做有創(chuàng)意品牌推廣活動策劃方案
  • 公路建設(shè)管理辦公室網(wǎng)站中國最好的營銷策劃公司
  • 石家莊做網(wǎng)站100個商業(yè)經(jīng)典案例
  • 網(wǎng)站開發(fā)文檔要求郴州網(wǎng)站seo外包
  • 個人簡歷免費(fèi)制作網(wǎng)站肥城市區(qū)seo關(guān)鍵詞排名
  • 怎樣做邪惡網(wǎng)站臨沂百度代理公司有幾個
  • 公司免費(fèi)網(wǎng)站制作營銷型企業(yè)網(wǎng)站的功能
  • 網(wǎng)站域名301是什么意思南寧seo網(wǎng)絡(luò)推廣
  • app介紹網(wǎng)站模板網(wǎng)站如何做seo推廣
  • 蘭州做網(wǎng)站咨詢蘭州做網(wǎng)站公司企業(yè)微信營銷系統(tǒng)