深入理解設計模式:工廠模式、單例模式
設計模式是軟件開發中解決常見問題的可復用方案。本文將詳細介紹兩種種重要的創建型設計模式:工廠模式、單例模式,并提供Java實現示例。
一、工廠模式
工廠模式是一種創建對象的設計模式,它提供了一種創建對象的最佳方式,而無需向客戶端暴露創建邏輯。
1.1 簡單工廠模式
簡單工廠模式由一個工廠類負責創建所有產品。
// 產品接口
interface Product {void operation();
}// 具體產品A
class ConcreteProductA implements Product {@Overridepublic void operation() {System.out.println("ConcreteProductA operation");}
}// 具體產品B
class ConcreteProductB implements Product {@Overridepublic void operation() {System.out.println("ConcreteProductB operation");}
}// 簡單工廠
class SimpleFactory {public static Product createProduct(String type) {if ("A".equals(type)) {return new ConcreteProductA();} else if ("B".equals(type)) {return new ConcreteProductB();}throw new IllegalArgumentException("Unknown product type");}
}// 客戶端代碼
public class Client {public static void main(String[] args) {Product productA = SimpleFactory.createProduct("A");productA.operation();Product productB = SimpleFactory.createProduct("B");productB.operation();}
}
1.2 工廠方法模式
工廠方法模式將實際創建對象的責任委托給子類。
// 產品接口
interface Product {void operation();
}// 具體產品A
class ConcreteProductA implements Product {@Overridepublic void operation() {System.out.println("ConcreteProductA operation");}
}// 具體產品B
class ConcreteProductB implements Product {@Overridepublic void operation() {System.out.println("ConcreteProductB operation");}
}// 工廠接口
interface Factory {Product createProduct();
}// 具體工廠A
class ConcreteFactoryA implements Factory {@Overridepublic Product createProduct() {return new ConcreteProductA();}
}// 具體工廠B
class ConcreteFactoryB implements Factory {@Overridepublic Product createProduct() {return new ConcreteProductB();}
}// 客戶端代碼
public class Client {public static void main(String[] args) {Factory factoryA = new ConcreteFactoryA();Product productA = factoryA.createProduct();productA.operation();Factory factoryB = new ConcreteFactoryB();Product productB = factoryB.createProduct();productB.operation();}
}
1.3 抽象工廠模式
抽象工廠模式提供一個接口,用于創建相關或依賴對象的家族,而不需要明確指定具體類。
// 產品A接口
interface ProductA {void operationA();
}// 產品B接口
interface ProductB {void operationB();
}// 具體產品A1
class ConcreteProductA1 implements ProductA {@Overridepublic void operationA() {System.out.println("ConcreteProductA1 operationA");}
}// 具體產品A2
class ConcreteProductA2 implements ProductA {@Overridepublic void operationA() {System.out.println("ConcreteProductA2 operationA");}
}// 具體產品B1
class ConcreteProductB1 implements ProductB {@Overridepublic void operationB() {System.out.println("ConcreteProductB1 operationB");}
}// 具體產品B2
class ConcreteProductB2 implements ProductB {@Overridepublic void operationB() {System.out.println("ConcreteProductB2 operationB");}
}// 抽象工廠接口
interface AbstractFactory {ProductA createProductA();ProductB createProductB();
}// 具體工廠1
class ConcreteFactory1 implements AbstractFactory {@Overridepublic ProductA createProductA() {return new ConcreteProductA1();}@Overridepublic ProductB createProductB() {return new ConcreteProductB1();}
}// 具體工廠2
class ConcreteFactory2 implements AbstractFactory {@Overridepublic ProductA createProductA() {return new ConcreteProductA2();}@Overridepublic ProductB createProductB() {return new ConcreteProductB2();}
}// 客戶端代碼
public class Client {public static void main(String[] args) {AbstractFactory factory1 = new ConcreteFactory1();ProductA productA1 = factory1.createProductA();ProductB productB1 = factory1.createProductB();productA1.operationA();productB1.operationB();AbstractFactory factory2 = new ConcreteFactory2();ProductA productA2 = factory2.createProductA();ProductB productB2 = factory2.createProductB();productA2.operationA();productB2.operationB();}
}
1.4 工廠模式的優缺點
優點:
- 封裝了對象的創建過程,客戶端無需了解具體產品類
- 可以輕松添加新產品而不影響現有代碼
- 遵循開閉原則
缺點:
- 引入了額外的類和接口,增加了系統復雜度
- 在某些情況下可能會增加系統的抽象程度和理解難度
1.5 適用場景
- 當一個類不知道它所需要創建的對象的類時
- 當一個類希望由子類來指定它所創建的對象時
- 當創建對象的過程涉及到復雜的業務邏輯時
二、單例模式
單例模式確保一個類只有一個實例,并提供一個全局訪問點。
2.1 餓漢式單例
public class EagerSingleton {// 在類加載時就創建實例private static final EagerSingleton INSTANCE = new EagerSingleton();// 私有構造函數,防止外部實例化private EagerSingleton() {// 防止通過反射創建多個實例if (INSTANCE != null) {throw new IllegalStateException("Singleton already initialized");}}// 提供全局訪問點public static EagerSingleton getInstance() {return INSTANCE;}// 示例方法public void doSomething() {System.out.println("Singleton is doing something");}
}
2.2 懶漢式單例(線程安全)
public class LazySingleton {// 初始不創建實例private static volatile LazySingleton instance;// 私有構造函數private LazySingleton() {// 防止通過反射創建多個實例if (instance != null) {throw new IllegalStateException("Singleton already initialized");}}// 提供全局訪問點,使用雙重檢查鎖定public static LazySingleton getInstance() {if (instance == null) {synchronized (LazySingleton.class) {if (instance == null) {instance = new LazySingleton();}}}return instance;}// 示例方法public void doSomething() {System.out.println("Singleton is doing something");}
}
2.3 枚舉實現單例
public enum EnumSingleton {INSTANCE;// 示例方法public void doSomething() {System.out.println("Enum Singleton is doing something");}
}// 使用方式
public class Client {public static void main(String[] args) {EnumSingleton.INSTANCE.doSomething();}
}
2.4 靜態內部類實現單例
public class StaticInnerSingleton {// 私有構造函數private StaticInnerSingleton() {}// 靜態內部類持有單例實例private static class SingletonHolder {private static final StaticInnerSingleton INSTANCE = new StaticInnerSingleton();}// 提供全局訪問點public static StaticInnerSingleton getInstance() {return SingletonHolder.INSTANCE;}// 示例方法public void doSomething() {System.out.println("Static inner class Singleton is doing something");}
}
2.5 單例模式的優缺點
優點:
- 保證一個類只有一個實例,減少內存開銷
- 提供全局訪問點,便于全局控制
- 實例只創建一次,避免多次實例化的性能開銷
缺點:
- 不適用于變化頻繁的對象
- 單例模式的擴展有一定難度
- 單例可能導致單一職責原則的違反
2.6 適用場景
- 需要頻繁創建和銷毀的對象
- 創建對象時耗時過多或耗費資源過多的對象
- 工具類對象
- 頻繁訪問數據庫或文件的對象
總結
本文詳細介紹了兩種種常用的創建型設計模式:工廠模式、單例模式和建造者模式。它們各自有不同的應用場景:
- 工廠模式:當需要將對象的創建與使用分離,或者需要創建一系列相關對象時使用。
- 單例模式:當系統中需要保證一個類只有一個實例,并提供全局訪問點時使用。
這些設計模式都是面向對象設計的重要工具,理解并正確應用它們可以幫助我們編寫出更加靈活、可維護的代碼。