Java 單例模式與工廠模式介紹
數(shù)據(jù)庫的四大特點:
原子性:不可再分
一致性:同成功,同失敗
隔離性:互不影響
持久性:不可逆轉(zhuǎn)
單例模式與工廠模式
1.單例模式
1.1 什么是單例模式:
常用的設(shè)計模式,單例對象的類只允許一個實例存在。在程序中多次使用同一個對象且作用相同的時候,為了防止頻繁的創(chuàng)造對象,單例模式可以讓程序在內(nèi)存中創(chuàng)建一個對象,所有的調(diào)用者都共享這一單例對象
1.2 單例的實現(xiàn)主要通過兩個步驟:
1.將該類的構(gòu)造方法定為私有方法,只有通過該類提供的靜態(tài)方法來得到該類的唯一實例
2.在該類中提供一個靜態(tài)方法,調(diào)用這個方法類持有的引用不為空就返回這個引用,若為空就創(chuàng)建該類的實例并將該類的實例的引用賦予該類保持的引用
1.3 單例模式類型分為餓漢式和懶漢式
1.餓漢式:在類加載的時候已經(jīng)創(chuàng)建好單例對象
1>構(gòu)造器私有化(防止new)
2>類的內(nèi)部創(chuàng)建對象
3>向外部暴露一個公共的靜態(tài)方法 getInstance
代碼:
class Singleton { //1.構(gòu)造器私有化,只能在內(nèi)部new對象 private Singleton(){ } //2.內(nèi)部實例化 private final static Singleton instance =new Singleton(); //3.提供get方法供外部使用,返回實例對象 public static Singleton getInstance(){ return instance; } }
優(yōu)點:在類加載時進(jìn)行實例化操作,避免線程同步問題
缺點:在類加載時進(jìn)行實例化操作,若未使用,造成內(nèi)存浪費
2.懶漢式:在使用對象是進(jìn)行加載
class Singleton{ private Singleton(){ } private static Singleton instance; public static synchronized Singleton getInstance(){ if(instance==null){ instance=new Singleton(); } return instance; } }
效率低,比如當(dāng)實例創(chuàng)建好之后,此時不會存在任何線程安全問題,但是每次訪問仍然要加鎖,導(dǎo)致效率低下
什么是工廠模式:
一、概述
工廠模式(Factory Pattern) 是一種 創(chuàng)建型設(shè)計模式,用于 封裝對象的創(chuàng)建邏輯,避免在代碼中直接實例化對象,從而提高代碼的 可維護(hù)性、擴(kuò)展性和解耦性。工廠模式的核心思想是:將對象的創(chuàng)建和使用分離,把對象創(chuàng)建邏輯封裝在一個工廠類中,從而提高代碼的可維護(hù)性和可擴(kuò)展性。
二、工廠模式分類
工廠模式包括 簡單工廠模式、工廠方法模式、抽象工廠模式,它們的擴(kuò)展性和復(fù)雜度逐步遞進(jìn):

三、工廠模式的實現(xiàn)
(一)簡單工廠模式(Simple Factory Pattern)
不屬于23種設(shè)計模式之一。簡單工廠模式又叫做:靜態(tài) 工廠方法模式。簡單工廠模式是工廠方法模式的一種特殊實現(xiàn)。
簡單工廠模式是工廠模式的基礎(chǔ)版本,它定義了一個工廠類來創(chuàng)建產(chǎn)品對象。
-
抽象產(chǎn)品 角色
-
具體產(chǎn)品 角色
-
工廠類 角色
示例1:兵工廠
抽象產(chǎn)品 角色:Weapon
public abstract class Weapon { /** * 所有的武器都可以攻擊。 */ public abstract void attack(); }
具體產(chǎn)品 角色:Dagger、Fighter、Tank
public class Dagger extends Weapon{ @Override public void attack() { System.out.println("砍丫的!!!"); } }
public class Fighter extends Weapon{ @Override public void attack() { System.out.println("戰(zhàn)斗機拋下小男孩!!!!"); } }
public class Tank extends Weapon{ @Override public void attack() { System.out.println("坦克開炮!!!"); } }
工廠類 角色
public class WeaponFactory { /** * 靜態(tài)方法。要獲取什么產(chǎn)品?就看你傳什么參數(shù),傳TANK獲取坦克,傳DAGGER獲取匕首,傳FIGHTER獲取戰(zhàn)斗機 * 簡單工廠模式中有一個靜態(tài)方法,所以被稱為:靜態(tài)工廠方法模式。 * @param weaponType * @return */ public static Weapon get(String weaponType){ if ("TANK".equals(weaponType)) { return new Tank(); } else if ("DAGGER".equals(weaponType)) { return new Dagger(); } else if ("FIGHTER".equals(weaponType)) { return new Fighter(); } else { throw new RuntimeException("不支持該武器的生產(chǎn)"); } } }
測試:
public class Test { public static void main(String[] args) { // 需要坦克 // 對于我客戶端來說,坦克的生產(chǎn)細(xì)節(jié),我不需要關(guān)心,我只需要向工廠索要即可。 // 簡單工廠模式達(dá)到了什么呢?職責(zé)分離。客戶端不需要關(guān)心產(chǎn)品的生產(chǎn)細(xì)節(jié)。 // 客戶端只負(fù)責(zé)消費。工廠類負(fù)責(zé)生產(chǎn)。一個負(fù)責(zé)生產(chǎn),一個負(fù)責(zé)消費。生產(chǎn)者和消費者分離了。這就是簡單工廠模式的作用。 Weapon tank = WeaponFactory.get("TANK"); tank.attack(); // 需要匕首 Weapon dagger = WeaponFactory.get("DAGGER"); dagger.attack(); // 需要戰(zhàn)斗機 Weapon fighter = WeaponFactory.get("FIGHTER"); fighter.attack(); } }
測試結(jié)果:

簡單工廠模式的缺點
缺點一:假設(shè)現(xiàn)在需要擴(kuò)展一個新的產(chǎn)品,WeaponFactory工廠類的代碼是需要修改的,顯然違背了OCP原則。
什么是OCP原則:軟件實體(類、模塊、函數(shù)等)應(yīng)對擴(kuò)展開放,對修改關(guān)閉。即在不修改現(xiàn)有代碼的前提下,通過擴(kuò)展實現(xiàn)新功能。
簡單工廠模式每次新增對象類型都要修改工廠類,違背該原則。
缺點二:工廠類的責(zé)任比較重大,不能出現(xiàn)任何問題,因為這個工廠類負(fù)責(zé)所有產(chǎn)品的生產(chǎn),稱為全能類,或者有人把它叫做上帝類。
這個工廠類一旦出問題,整個系統(tǒng)必然全部癱瘓。(不要把所有雞蛋放到一個籃子里面哦。)
(二)工廠方法模式
工廠方法模式將對象創(chuàng)建延遲到子類,每個具體工廠類負(fù)責(zé)創(chuàng)建特定類型的產(chǎn)品。
工廠方法模式既保留了簡單工廠模式的優(yōu)點,同時又解決了簡單工廠模式的缺點。 工廠方法模式的角色包括:
-
抽象工廠角色
-
具體工廠角色
-
抽象產(chǎn)品角色
-
具體產(chǎn)品角色
示例1:兵工廠
就是把工廠開成專門的坦克制造廠和飛機制造廠,各種廠抽象出一個接口廠
抽象產(chǎn)品角色 Weapon
abstract public class Weapon {
public abstract void attack();
}
具體產(chǎn)品角色 Dagger Gun
public class Dagger extends Weapon{
@Override
public void attack() {
System.out.println("砍丫的!!!");
}
}
public class Gun extends Weapon{
@Override
public void attack() {
System.out.println("開槍射擊!!!");
}
}
抽象工廠角色 WeaponFactory
abstract public class WeaponFactory {
/**
* 這個方法不是靜態(tài)的。是實例方法。
* @return
*/
public abstract Weapon get();
}
具體工廠角色 DaggerFactory GunFactory
public class GunFactory extends WeaponFactory{
@Override
public Weapon get() {
return new Gun();
}
}
public class DaggerFactory extends WeaponFactory{
@Override
public Weapon get() {
return new Dagger();
}
}
Test
public class Test {
public static void main(String[] args) {
WeaponFactory weaponFactory = new DaggerFactory();
Weapon dagger = weaponFactory.get();
dagger.attack();
WeaponFactory weaponFactory1 = new GunFactory();
Weapon gun = weaponFactory1.get();
gun.attack();
}
}
測試結(jié)果

如果想擴(kuò)展一個新的產(chǎn)品,只要新增一個產(chǎn)品類,再新增一個該產(chǎn)品對應(yīng)的工廠即可,例如新增:戰(zhàn)斗機
public class Fighter extends Weapon{
@Override
public void attack() {
System.out.println("戰(zhàn)斗機發(fā)射核彈!");
}
}
public class FighterFactory extends WeaponFactory{
@Override
public Weapon get() {
return new Fighter();
}
}
客戶端程序:
public class Client {
public static void main(String[] args) {
WeaponFactory factory = new GunFactory();
Weapon weapon = factory.get();
weapon.attack();
WeaponFactory factory1 = new FighterFactory();
Weapon weapon1 = factory1.get();
weapon1.attack();
WeaponFactory factory2 = new DaggerFactory();
Weapon weapon2 = factory2.get();
weapon2.attack();
}
}
執(zhí)行結(jié)果如下:

我們可以看到在進(jìn)行功能擴(kuò)展的時候,不需要修改之前的源代碼,顯然工廠方法模式符合OCP原則。
什么是OCP原則:
軟件實體(類、模塊、函數(shù)等)應(yīng)對擴(kuò)展開放,對修改關(guān)閉。即在不修改現(xiàn)有代碼的前提下,通過擴(kuò)展實現(xiàn)新功能。
工廠方法模式的優(yōu)點:
一個調(diào)用者想創(chuàng)建一個對象,只要知道其名稱就可以了。
擴(kuò)展性高,如果想增加一個產(chǎn)品,只要擴(kuò)展一個工廠類就可以。
屏蔽產(chǎn)品的具體實現(xiàn),調(diào)用者只關(guān)心產(chǎn)品的接口。
工廠方法模式的缺點:
每次增加一個產(chǎn)品時,都需要增加一個具體類和對象實現(xiàn)工廠,使得系統(tǒng)中類的個數(shù)成倍增加,在一定程度上增加了系統(tǒng)的復(fù)雜度,同時也增加了系統(tǒng)具體類的依賴。這并不是什么好事。
示例2:日志記錄器工廠
假設(shè)我們需要創(chuàng)建不同類型的日志記錄器(文件日志、數(shù)據(jù)庫日志),使用工廠方法模式可以這樣設(shè)計:
// 日志記錄器接口
public interface Logger {
void log(String message);
}
步驟 2:實現(xiàn)具體產(chǎn)品類
// 文件日志記錄器
public class FileLogger implements Logger {
@Override
public void log(String message) {
System.out.println("文件日志: " + message);
}
}
// 數(shù)據(jù)庫日志記錄器
public class DatabaseLogger implements Logger {
@Override
public void log(String message) {
System.out.println("數(shù)據(jù)庫日志: " + message);
}
}
步驟 3:定義工廠接口
// 日志記錄器工廠接口
public interface LoggerFactory {
Logger createLogger();
}
步驟 4:實現(xiàn)具體工廠類
// 文件日志工廠
public class FileLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
return new FileLogger();
}
}
// 數(shù)據(jù)庫日志工廠
public class DatabaseLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
return new DatabaseLogger();
}
}
步驟 5:客戶端使用
public class Client {
public static void main(String[] args) {
// 創(chuàng)建文件日志工廠
LoggerFactory fileLoggerFactory = new FileLoggerFactory();
Logger fileLogger = fileLoggerFactory.createLogger();
fileLogger.log("這是文件日志");
// 創(chuàng)建數(shù)據(jù)庫日志工廠
LoggerFactory databaseLoggerFactory = new DatabaseLoggerFactory();
Logger databaseLogger = databaseLoggerFactory.createLogger();
databaseLogger.log("這是數(shù)據(jù)庫日志");
}
}
輸出結(jié)果:
文件日志: 這是文件日志
數(shù)據(jù)庫日志: 這是數(shù)據(jù)庫日志
(三)抽象工廠模式
抽象工廠模式相對于工廠方法模式來說,就是工廠方法模式是針對一個產(chǎn)品系列的,而抽象工廠模式是針對多個產(chǎn)品系列的,即工廠方法模式是一個產(chǎn)品系列一個工廠類,而抽象工廠模式是多個產(chǎn)品系列一個工廠類。
抽象工廠中包含4個角色:
抽象工廠角色
- 抽象工廠角色
- 具體工廠角色
- 抽象產(chǎn)品角色
- 具體產(chǎn)品角色
抽象工廠模式的類圖如下:

抽象工廠模式代碼如下:
第一部分:武器產(chǎn)品族
public abstract class Weapon {
public abstract void attack();
}
public class Gun extends Weapon{
@Override
public void attack() {
System.out.println("開槍射擊!");
}
}
public class Dagger extends Weapon{
@Override
public void attack() {
System.out.println("砍丫的!");
}
}
第二部分:水果產(chǎn)品族
public abstract class Fruit {
/**
* 所有果實都有一個成熟周期。
*/
public abstract void ripeCycle();
}
public class Orange extends Fruit{
@Override
public void ripeCycle() {
System.out.println("橘子的成熟周期是10個月");
}
}
public class Apple extends Fruit{
@Override
public void ripeCycle() {
System.out.println("蘋果的成熟周期是8個月");
}
}
第四部分:具體工廠類
public class WeaponFactory extends AbstractFactory{
public Weapon getWeapon(String type){
if (type == null || type.trim().length() == 0) {
return null;
}
if ("Gun".equals(type)) {
return new Gun();
} else if ("Dagger".equals(type)) {
return new Dagger();
} else {
throw new RuntimeException("無法生產(chǎn)該武器");
}
}
@Override
public Fruit getFruit(String type) {
return null;
}
}
public class FruitFactory extends AbstractFactory{
@Override
public Weapon getWeapon(String type) {
return null;
}
public Fruit getFruit(String type){
if (type == null || type.trim().length() == 0) {
return null;
}
if ("Orange".equals(type)) {
return new Orange();
} else if ("Apple".equals(type)) {
return new Apple();
} else {
throw new RuntimeException("我家果園不產(chǎn)這種水果");
}
}
}
第五部分:客戶端程序
public class Client {
public static void main(String[] args) {
// 客戶端調(diào)用方法時只面向AbstractFactory調(diào)用方法。
AbstractFactory factory = new WeaponFactory(); // 注意:這里的new WeaponFactory()可以采用 簡單工廠模式 進(jìn)行隱藏。
Weapon gun = factory.getWeapon("Gun");
Weapon dagger = factory.getWeapon("Dagger");
gun.attack();
dagger.attack();
AbstractFactory factory1 = new FruitFactory(); // 注意:這里的new FruitFactory()可以采用 簡單工廠模式 進(jìn)行隱藏。
Fruit orange = factory1.getFruit("Orange");
Fruit apple = factory1.getFruit("Apple");
orange.ripeCycle();
apple.ripeCycle();
}
}
執(zhí)行結(jié)果:

抽象工廠模式的優(yōu)缺點:
-
優(yōu)點:當(dāng)一個產(chǎn)品族中的多個對象被設(shè)計成一起工作時,它能保證客戶端始終只使用同一個產(chǎn)品族中的對象。
-
缺點:產(chǎn)品族擴(kuò)展非常困難,要增加一個系列的某一產(chǎn)品,既要在AbstractFactory里加代碼,又要在具體的里面加代碼。
抽象工廠模式的優(yōu)缺點:
- 優(yōu)點:將具體產(chǎn)品創(chuàng)建封裝,客戶端無需依賴具體產(chǎn)品類。
- 缺點:擴(kuò)展產(chǎn)品族困難,新增產(chǎn)品需修改抽象工廠接口及所有子類。
Java 中工廠模式的實際應(yīng)用
示例:數(shù)據(jù)庫連接工廠
// 數(shù)據(jù)庫連接接口
public interface DBConnection {
void connect();
}
// MySQL 連接
public class MySQLConnection implements DBConnection {
@Override
public void connect() {
System.out.println("連接到 MySQL 數(shù)據(jù)庫");
}
}
// Oracle 連接
public class OracleConnection implements DBConnection {
@Override
public void connect() {
System.out.println("連接到 Oracle 數(shù)據(jù)庫");
}
}
// 數(shù)據(jù)庫連接工廠
public class DBConnectionFactory {
public static DBConnection getConnection(String dbType) {
if (dbType == null) {
return null;
}
if (dbType.equalsIgnoreCase("MYSQL")) {
return new MySQLConnection();
} else if (dbType.equalsIgnoreCase("ORACLE")) {
return new OracleConnection();
}
throw new IllegalArgumentException("不支持的數(shù)據(jù)庫類型: " + dbType);
}
}
// 客戶端使用
public class Client {
public static void main(String[] args) {
DBConnection mysqlConn = DBConnectionFactory.getConnection("MYSQL");
mysqlConn.connect();
DBConnection oracleConn = DBConnectionFactory.getConnection("ORACLE");
oracleConn.connect();
}
}
總結(jié)
工廠模式是一種非常實用的創(chuàng)建型設(shè)計模式,它將對象的創(chuàng)建和使用分離,提高了代碼的可維護(hù)性和可擴(kuò)展性。在實際開發(fā)中,可以根據(jù)需求選擇合適的工廠模式:
簡單工廠:適用于創(chuàng)建對象邏輯簡單且產(chǎn)品種類較少的場景。
工廠方法:適用于需要擴(kuò)展性,經(jīng)常新增產(chǎn)品的場景。
抽象工廠:適用于創(chuàng)建一系列相關(guān)產(chǎn)品的場景
工廠模式原文鏈接:https://blog.csdn.net/m0_73941339/article/details/148344378

浙公網(wǎng)安備 33010602011771號