Java之單例模式、多例模式、列舉、工廠模式
第一章 單例設計模式
知識點-- 單例設計模式的概述
目標
正常情況下一個類可以建立多個物件
public class Person(){
// 預設生成一個公共的空參構造方法
}
// 測試類
public static void main(String[] args) {
// 正常情況下一個類可以建立多個物件
Person p1 = new Person();
Person p2 = new Person();
Person p3 = new Person();
// ...
}
但是有些時候的某些類, 我們希望只能建立單一的一個物件, 這時候我們需要使用到單例設計模式, 下面我們來介紹一下單例設計模式.
路徑
- 單例設計模式的作用
- 單例設計模式實現步驟
- 單例設計模式的型別
講解
單例設計模式的作用
單例模式,是一種常用的軟體設計模式。通過單例模式可以保證系統中,應用該模式的這個類只有一個例項。即一個類只有一個物件例項。
單例設計模式實現步驟
- 將構造方法私有化,使其不能在類的外部通過new關鍵字例項化該類物件。
- 在該類內部產生一個唯一的例項化物件 private
- 定義一個靜態方法返回這個唯一物件。
例設計模式的型別
根據例項化物件的時機單例設計模式又分為以下兩種:
- 餓漢單例設計模式
- 懶漢單例設計模式
知識點-- 餓漢式單例設計模式
目標
- 掌握單例設計模式的書寫
路徑
- 單例設計模式 --- 餓漢式
講解
餓漢單例設計模式就是使用類的時候已經將物件建立完畢,不管以後會不會使用到該例項化物件,先建立了再說。很著急的樣子,故被稱為“餓漢模式”。
程式碼如下:
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,保證其同步安全。
小結
單例模式可以保證系統中一個類只有一個物件例項。
實現單例模式的步驟:
- 將構造方法私有化,使其不能在類的外部通過new關鍵字例項化該類物件。
- 在該類內部產生一個唯一的例項化物件,並且將其封裝為private static型別的成員變數。
- 定義一個靜態方法返回這個唯一物件。
第二章 多例設計模式
知識點--多例設計模式
目標
- 掌握多例設計模式的書寫
路徑
- 多例設計模式的作用
- 實現步驟
- 實現程式碼
- 測試結果
講解
多例設計模式的作用
多例模式,是一種常用的軟體設計模式。通過多例模式可以保證系統中,應用該模式的類有固定數量的例項。多例類要自我建立並管理自己的例項,還要向外界提供獲取本類例項的方法。
實現步驟
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);
}
}
}
小結
多例模式可以保證系統中一個類有固定個數的例項, 在實現需求的基礎上, 能夠提高例項的複用性.
實現多例模式的步驟:
- 建立一個類, 將構造方法私有化,使其不能在類的外部通過new關鍵字例項化該類物件。
- 在類中定義該類被建立的總數量
- 在類中定義存放類例項的list集合
- 在類中提供靜態程式碼塊,在靜態程式碼塊中建立類的例項
- 提供獲取類例項的靜態方法
第四章 列舉
知識點--列舉的概述和定義
目標
- 掌握列舉的定義和使用
路徑
- 引入不使用列舉存在的問題
- 列舉的概述
- 列舉的定義
- 列舉的使用
講解
不使用列舉存在的問題
假設我們要定義一個人類,人類中包含姓名和性別。通常會將性別定義成字串型別,效果如下:
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;
}
}
列舉的使用
- 定義列舉:BOY表示男,GIRL表示女
enum Sex {
BOY, GIRL; // 男,女
}
- 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方法
}
- 使用是隻能傳入列舉中的固定值
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個測試類就只和工廠類有關係
工廠模式的作用
將前端程式碼與要建立的物件分開,前端不需要直接建立物件,也就不需要關心建立物件時需要的資料。只需要通過工廠類獲取物件即可。
- 解決類與類之間的耦合問題
案例演示
需求
- 編寫一個Car介面, 提供run方法
- 編寫一個Falali類實現Car介面,重寫run方法
- 編寫一個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外掛(連線網路使用)
- 第一步
- 第二步:
- 第三步:
- 第四步:
-
安裝完畢後,重啟IDEA。
-
新建一個類: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程式
提供一個工廠類,在工廠類中提供一個公共的靜態方法,用來建立類的物件