1. 程式人生 > 實用技巧 >Java之單例模式、多例模式、列舉、工廠模式

Java之單例模式、多例模式、列舉、工廠模式

第一章 單例設計模式

知識點-- 單例設計模式的概述

目標

正常情況下一個類可以建立多個物件

public class Person(){
    // 預設生成一個公共的空參構造方法
}
// 測試類
public static void main(String[] args) {
	// 正常情況下一個類可以建立多個物件
	Person p1 = new Person();
	Person p2 = new Person();
	Person p3 = new Person();
    // ...
}

但是有些時候的某些類, 我們希望只能建立單一的一個物件, 這時候我們需要使用到單例設計模式, 下面我們來介紹一下單例設計模式.

路徑

  • 單例設計模式的作用
  • 單例設計模式實現步驟
  • 單例設計模式的型別

講解

單例設計模式的作用

單例模式,是一種常用的軟體設計模式。通過單例模式可以保證系統中,應用該模式的這個類只有一個例項。即一個類只有一個物件例項。

單例設計模式實現步驟

  1. 將構造方法私有化,使其不能在類的外部通過new關鍵字例項化該類物件。
  2. 在該類內部產生一個唯一的例項化物件 private
  3. 定義一個靜態方法返回這個唯一物件。

例設計模式的型別

根據例項化物件的時機單例設計模式又分為以下兩種:

  1. 餓漢單例設計模式
  2. 懶漢單例設計模式

知識點-- 餓漢式單例設計模式

目標

  • 掌握單例設計模式的書寫

路徑

  • 單例設計模式 --- 餓漢式

講解

餓漢單例設計模式就是使用類的時候已經將物件建立完畢,不管以後會不會使用到該例項化物件,先建立了再說。很著急的樣子,故被稱為“餓漢模式”。

程式碼如下:

public class Person {
    // 餓漢式單例設計模式: 比較著急,不管會不會使用這個類的物件,都先建立了再說
    // 1.構造方法私有化
    private Person(){

    }

    // 2.在該類的內部建立一個該類的物件
    private static final Person P = new Person();

    // 3.提供一個靜態方法,供外界獲取該類的物件
    public static Person getInstance(){
        return P;
    }

    // 成員方法
    public static void sleep(){
        System.out.println("睡覺");
    }
}
public class Test {
    public static void main(String[] args) {
        // 驗證
        Person p1 = Person.getInstance();
        Person p2 = Person.getInstance();
        Person p3 = Person.getInstance();
        Person p4 = Person.getInstance();
        System.out.println(p1);
        System.out.println(p2);
        System.out.println(p3);
        System.out.println(p4);
    }
}


知識點-- 懶漢式單例設計模式

目標

  • 掌握懶漢式單例設計模式的書寫

路徑

  • 單例設計模式 --- 懶漢式

講解

懶漢單例設計模式就是呼叫getInstance()方法時例項才被建立,先不急著例項化出物件,等要用的時候才例項化出物件。不著急,故稱為“懶漢模式”。

程式碼如下:

public class Person {
    // 懶漢式單例: 不著急,只要當你呼叫了getInstance靜態方法獲取物件的時候,就建立,其他時候不建立
    // 1. 將構造方法私有化,使其不能在類的外部通過new關鍵字例項化該類物件。
    private Person(){

    }

    // 2. 在該類內部產生一個唯一的例項化物件
    private static Person p ;// 預設值為null

    // 3. 定義一個靜態方法返回這個唯一物件。
    public static synchronized Person getInstance(){
        // 建立Person類的唯一物件
        // 判斷一下,如果p這個成語變數的值為null,就建立,不為null,說明該物件已經建立了,直接返回即可
        if (p == null){
            p = new Person();
        }
        return p;
    }

    // ...
}

public class Test {
    public static void main(String[] args) {
        Person p1 = Person.getInstance();
        Person p2 = Person.getInstance();
        Person p3 = Person.getInstance();

        System.out.println(p1);
        System.out.println(p2);
        System.out.println(p3);


    }
}

注意:懶漢單例設計模式在多執行緒環境下可能會例項化出多個物件,不能保證單例的狀態,所以加上關鍵字:synchronized,保證其同步安全。

小結

單例模式可以保證系統中一個類只有一個物件例項。

實現單例模式的步驟:

  1. 將構造方法私有化,使其不能在類的外部通過new關鍵字例項化該類物件。
  2. 在該類內部產生一個唯一的例項化物件,並且將其封裝為private static型別的成員變數。
  3. 定義一個靜態方法返回這個唯一物件。

第二章 多例設計模式

知識點--多例設計模式

目標

  • 掌握多例設計模式的書寫

路徑

  • 多例設計模式的作用
  • 實現步驟
  • 實現程式碼
  • 測試結果

講解

多例設計模式的作用

多例模式,是一種常用的軟體設計模式。通過多例模式可以保證系統中,應用該模式的類有固定數量的例項。多例類要自我建立並管理自己的例項,還要向外界提供獲取本類例項的方法。

實現步驟

​ 1.建立一個類, 將構造方法私有化,使其不能在類的外部通過new關鍵字例項化該類物件。

​ 2.在該類內部產生固定數量的例項化物件 ----> 集合

​ 3.提高一個靜態方法來隨機獲取一個該了的例項化物件

實現程式碼

public class Person {
    // 使用多例設計模式: 保證程式執行期間該類只有固定數量的物件產生
    // 1.建立一個類,  將構造方法私有化,使其不能在類的外部通過new關鍵字例項化該類物件。
    private Person(){
    }

    // 2.在該類內部產生固定數量的例項化物件 ----> 集合  只能產生依次固定數量的物件

    // 2.1 定義一個存放該類物件的集合
    private static ArrayList<Person> list = new ArrayList<>();

    // 2.2 在靜態程式碼塊中,建立固定數量的物件,新增到集合中
    static {
        // 建立固定數量的該類物件
        for (int i = 0; i < 3; i++) {
            Person p = new Person();
            list.add(p);
        }
    }

    // 3.提高一個靜態方法來隨機獲取一個該了的例項化物件
    public static Person getInstance(){
        // 建立一個Random物件
        Random r = new Random();
        // 隨機產生一個list集合的索引
        int index = r.nextInt(list.size());// [0,3) 0,1,2
        // 根據索引獲取物件
        Person p = list.get(index);
        // 返回物件
        return p;
    }
}

測試結果

public class Test {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Person p1 = Person.getInstance();
            System.out.println(p1);
        }

    }
}

小結

多例模式可以保證系統中一個類有固定個數的例項, 在實現需求的基礎上, 能夠提高例項的複用性.

實現多例模式的步驟:

  1. 建立一個類, 將構造方法私有化,使其不能在類的外部通過new關鍵字例項化該類物件。
  2. 在類中定義該類被建立的總數量
  3. 在類中定義存放類例項的list集合
  4. 在類中提供靜態程式碼塊,在靜態程式碼塊中建立類的例項
  5. 提供獲取類例項的靜態方法

第四章 列舉

知識點--列舉的概述和定義

目標

  • 掌握列舉的定義和使用

路徑

  • 引入不使用列舉存在的問題
  • 列舉的概述
  • 列舉的定義
  • 列舉的使用

講解

不使用列舉存在的問題

假設我們要定義一個人類,人類中包含姓名和性別。通常會將性別定義成字串型別,效果如下:

public class Person {
    private String name;
    private String sex;

    public Person() {
    }

    public Person(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }
	
    // 省略get/set/toString方法
}
public class Demo01 {
    public static void main(String[] args) {
        Person p1 = new Person("張三", "男");
        Person p2 = new Person("張三", "abc"); // 因為性別是字串,所以我們可以傳入任意字串
    }
}

不使用列舉存在的問題:可以給性別傳入任意的字串,導致性別是非法的資料,不安全。

列舉的概念

列舉是一種用來表示固定個數值的引用資料型別,例如性別,季節,方向等等這些資料都是有固定個數數值的,java中的列舉是有固定個數物件的"特殊類"。

定義列舉的格式

public enum 列舉名 {
    // 第一行都是羅列列舉例項,這些列舉例項直接寫大寫名字即可。
    例項,例項,例項,...;
}

public enum Sex {
    BOY,GIRL,YAO
}


public enum Season {
    SPRING, SUMMER, AUTUMN, WINTER;
}

public enum Direction {
    UP,DOWN,LEFT,RIGHT
}


// 使用列舉
public class Test {

    public static void main(String[] args) {
        /*
               概述:列舉是一種用來表示固定個數值的引用資料型別,例如性別,季節,方向等等這些資料都是有固定個數數值的
               格式:
                    public enum 列舉名{
                        列舉值,列舉值,列舉值,....
                    }

                    規範: 列舉值的名稱所有字母大寫
              使用列舉:  其實就是把列舉當成一個數據型別來使用
              列舉值;  列舉名.列舉值
         */
        // 定義一個Sex列舉型別的變數,並賦值
        Sex sex1 = Sex.BOY;
        Sex sex2 = Sex.GIRL;
        Sex sex3 = Sex.YAO;

        // 定義一個Direction列舉型別的變數,並賦值
        Direction d1 = Direction.UP;
        Direction d2 = Direction.DOWN;

    }
}

列舉的使用

  1. 定義列舉:BOY表示男,GIRL表示女
enum Sex {
    BOY, GIRL; // 男,女
}
  1. Perosn中的性別有String型別改為Sex列舉型別
public class Person {
    private String name;
    private Sex sex;

    public Person() {
    }

    public Person(String name, Sex sex) {
        this.name = name;
        this.sex = sex;
    }
    // 省略get/set/toString方法
}
  1. 使用是隻能傳入列舉中的固定值
public class Demo02 {
    public static void main(String[] args) {
        // 使用列舉格式: 列舉型別.列舉值
        Person p1 = new Person("張三", Sex.BOY);
        Person p2 = new Person("張三", Sex.GIRL);
        Person p3 = new Person("張三", "abc");// 編譯報錯
    }
}

知識點--列舉的其他內容(聽聽就好)

目標

  • 瞭解列舉的其他內容

路徑

  • 瞭解列舉的其他內容

講解

列舉的本質其實就是一個使用了多例設計模式的類,所以列舉中還可以有成員變數,成員方法等。

列舉的本質是一個類,我們剛才定義的Sex列舉最終效果如下:

public enum Sex {
    BOY, GIRL; // 男,女
}
public enum Sex {
    BOY(18), GIRL(16);

    public int age;

    Sex(int age) {
        this.age = age;
    }

    public void showAge() {
        System.out.println("年齡是: " + age);
    }
}
public class Demo03 {
    public static void main(String[] args) {
        Person p1 = new Person("張三", Sex.BOY);
        Person p2 = new Person("張三", Sex.GIRL);

        Sex.BOY.showAge();
        Sex.GIRL.showAge();
    }
}

執行效果:

第四章 工廠設計模式

知識點-- 工廠模式的概述

目標

  • 工廠模式其實就是用來幫我們建立物件的, 那麼它到底有哪些特點, 我們來學習一下.

路徑

  • 工廠模式的介紹
  • 工廠模式的作用
  • 案例演示

講解

工廠模式的介紹

​ 工廠模式(Factory Pattern)是 Java 中最常用的設計模式之一。這種型別的設計模式屬於建立型模式,它提供了一種建立物件的最佳方式。之前我們建立類物件時, 都是使用new 物件的形式建立, 除new 物件方式以外, 工廠模式也可以建立物件.

耦合度: 類與類之間的關係,如果關係比較強,高耦合, 如果關係比較弱,低耦合

10個類:

10個測試類: 需要建立這10個類的物件

以前: 直接通過new 來建立 10個測試類都要和這個10個類關係起來

現在: 使用工廠模式,定義一個工廠類,專門用來建立這10個類的物件, 並提供獲取的方法,

​ 在10個測試類中建立這10個類的物件,只需要使用工廠類來建立就行了,10個測試類就只和工廠類有關係

工廠模式的作用

將前端程式碼與要建立的物件分開,前端不需要直接建立物件,也就不需要關心建立物件時需要的資料。只需要通過工廠類獲取物件即可。

  • 解決類與類之間的耦合問題

案例演示

需求
  1. 編寫一個Car介面, 提供run方法
  2. 編寫一個Falali類實現Car介面,重寫run方法
  3. 編寫一個Benchi類實現Car介面,重寫run方法

提供一個工廠類,可以用來生產汽車物件

實現程式碼

1.編寫一個Car介面, 提供run方法

public interface Car {
    public void run();
}

2.編寫一個Falali類實現Car介面,重寫run方法

public class Falali implements Car {
    @Override
    public void run() {
        System.out.println("法拉利以每小時500公里的速度在奔跑.....");
    }
}

3.編寫一個Benchi類實現Car介面

public class Benchi implements Car {
    @Override
    public void run() {
        System.out.println("賓士汽車以每秒1米的速度在挪動.....");
    }
}

4.提供一個CarFactory(汽車工廠),用於生產汽車物件

public class CarFactory {
    /**
     * @param id : 車的標識
     *           benchi : 代表需要建立Benchi類物件
     *           falali : 代表需要建立Falali類物件
     *           如果傳入的車標識不正確,代表當前工廠生成不了當前車物件,則返回null
     * @return
     */
    public Car createCar(String id){
        if("falali".equals(id)){
            return new Falali();
        }else if("benchi".equals(id)){
            return new Benchi();
        }
        return null;
    }
}

5.定義CarFactoryTest測試汽車工廠

public class CarFactoryTest {
    public static void main(String[] args) {
        CarFactory carFactory = new CarFactory();
        Car benchi = carFactory.createCar("benchi");
        benchi.run();
        Car falali = carFactory.createCar("falali");
        falali.run();
    }
}

小結

  • 工廠模式的存在可以改變建立類的物件的方式,解決類與類之間的耦合.

第五章 Lombok【自學擴充套件】

知識點-- Lombok的使用

目標

  • 能夠使用Lombok

路徑

  • lombok介紹
  • lombok使用

講解

lombok介紹

  • lombok可以使用註解的方式讓一些程式碼變的簡潔 方便
  • 實體類中有一些固定的程式碼:構造方法,getter/setter、equals、hashcode、toString方法都是固定的,寫出來看著比較麻煩。而Lombok能通過註解的方式,在編譯時自動為屬性生成這些程式碼。

lombok使用

​ 1. 新增lombox的jar包:

​ 將lombok.jar(本例使用版本:1.18.10),新增到模組目錄下,並新增到ClassPath

​ 2. 為IDEA新增lombok外掛(連線網路使用)

  • 第一步

  • 第二步:

  • 第三步:

  • 第四步:

  1. 安裝完畢後,重啟IDEA。

  2. 新建一個類:Student

lombok常用註解

  • @Getter和@Setter

    • 作用:生成成員變數的get和set方法。
    • 寫在成員變數上,指對當前成員變數有效。
    • 寫在類上,對所有成員變數有效。
    • 注意:靜態成員變數無效。
  • @ToString:

    • 作用:生成toString()方法。
    • 該註解只能寫在類上。
  • @NoArgsConstructor和@AllArgsConstructor

    • @NoArgsConstructor:無引數構造方法。
    • @AllArgsConstructor:滿引數構造方法。
    • 註解只能寫在類上。
  • @EqualsAndHashCode

    • 作用:生成hashCode()和equals()方法。
    • 註解只能寫在類上。
  • @Data

    • 作用: 生成setter/getter、equals、hashCode、toString方法,如為final屬性,則不會為該屬性生成setter方法。

    • 註解只能寫在類上。

總結

- 能夠說出單例設計模式的好處
    作用: 可以保證使用該模式定義的類只有一個物件產生
    實現步驟:
		1.構造方法私有化,使其不能在其他類中通過new呼叫構造方法來建立物件
        2.在類的內部建立一個該類的物件
        3.提供一個公共的靜態方法,用來供外界獲取該類的唯一物件
   餓漢式和懶漢式(看建立物件的時機)
- 能夠說出多例模式的好處
    作用: 可以保證使用該模式定義的類有固定數量的物件產生
    實現步驟:
			1.構造方法私有化,使其不能在其他類中通過new呼叫構造方法來建立物件
            2.在類的內部建立固定數量的該類物件
            3.提供一個公共的靜態方法,用來供外界獲取該類的物件
- 能夠定義列舉
     定義列舉:  
			public enum 列舉名{
                列舉值,列舉值,...
            }
	 列舉的使用:
			獲取列舉值: 列舉名.列舉值
            給列舉型別的變數賦值:  列舉型別 變數名 = 列舉名.列舉值;
- 能夠使用工廠模式編寫java程式
       提供一個工廠類,在工廠類中提供一個公共的靜態方法,用來建立類的物件