Java中常見的設計模式
Java 中有 23 種經典設計模式,通常被分為三大類:創建型、結構型和行為型。每個設計模式都解決了不同類型的設計問題。以下是幾種常見設計模式的總結,并附帶了實際應用場景、示例代碼和詳細的注釋說明。
一、創建型設計模式
這些設計模式關注對象的創建方式,避免在代碼中直接創建對象。
1. 單例模式(Singleton Pattern)
-
定義:
單例模式確保一個類只有一個實例,并提供一個全局的訪問點來獲取該實例。 -
應用場景:
常用于配置類、數據庫連接池、日志類等。 -
示例代碼:
public class Singleton {// 1. 聲明一個私有靜態實例變量private static Singleton instance;// 2. 私有構造方法,防止外部創建多個實例private Singleton() {}// 3. 提供公共的靜態方法,返回唯一實例public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) { // 4. 雙重檢查鎖定,確保線程安全if (instance == null) {instance = new Singleton(); // 5. 創建實例}}}return instance; // 6. 返回單例實例}
}
- 解釋:
通過private構造器防止外部創建多個實例。
使用getInstance()方法獲取唯一的實例,采用雙重鎖定來保證線程安全。
2. 工廠模式(Factory Pattern)
-
定義:
工廠模式提供一個創建對象的接口,但由子類決定實例化哪一個類。它讓客戶端無需知道具體的實現類,就可以創建出所需的對象。 -
應用場景:
用于創建對象的場景,尤其是類的實例化非常復雜或需要根據不同條件創建不同的對象時。 -
示例代碼:
// 1. 定義產品接口
public interface Animal {void sound();
}// 2. 具體產品類:Dog
public class Dog implements Animal {public void sound() {System.out.println("Woof!");}
}// 3. 具體產品類:Cat
public class Cat implements Animal {public void sound() {System.out.println("Meow!");}
}// 4. 工廠類,負責創建產品實例
public class AnimalFactory {public Animal createAnimal(String type) {if ("dog".equalsIgnoreCase(type)) {return new Dog(); // 5. 創建Dog對象} else if ("cat".equalsIgnoreCase(type)) {return new Cat(); // 6. 創建Cat對象}return null; // 7. 返回null表示無法創建對象}
}// 8. 客戶端代碼
public class Client {public static void main(String[] args) {AnimalFactory factory = new AnimalFactory(); // 9. 創建工廠對象Animal dog = factory.createAnimal("dog"); // 10. 通過工廠創建Dog對象dog.sound(); // 11. 輸出:Woof!Animal cat = factory.createAnimal("cat"); // 12. 通過工廠創建Cat對象cat.sound(); // 13. 輸出:Meow!}
}
- 解釋:
AnimalFactory負責根據參數創建不同的Animal類型對象,避免客戶端直接依賴具體類。
3. 抽象工廠模式(Abstract Factory Pattern)
- 定義:
抽象工廠模式提供一個接口,用來創建一系列相關或相互依賴的對象,而無需指定具體的類。 - 應用場景:
需要創建一系列相關的對象,而無需指定具體類。
用于產品族的創建,確保一系列相關的對象符合某種約定。 - 示例代碼:
// 1. 定義抽象產品接口:ProductA
public interface ProductA {void doSomething();
}// 2. 具體產品A1
public class ProductA1 implements ProductA {public void doSomething() {System.out.println("ProductA1 does something");}
}// 3. 具體產品A2
public class ProductA2 implements ProductA {public void doSomething() {System.out.println("ProductA2 does something");}
}// 4. 定義抽象產品接口:ProductB
public interface ProductB {void doSomethingElse();
}// 5. 具體產品B1
public class ProductB1 implements ProductB {public void doSomethingElse() {System.out.println("ProductB1 does something else");}
}// 6. 具體產品B2
public class ProductB2 implements ProductB {public void doSomethingElse() {System.out.println("ProductB2 does something else");}
}// 7. 定義抽象工廠接口
public interface AbstractFactory {ProductA createProductA();ProductB createProductB();
}// 8. 具體工廠A1
public class ConcreteFactoryA1 implements AbstractFactory {public ProductA createProductA() {return new ProductA1(); // 9. 返回ProductA1}public ProductB createProductB() {return new ProductB1(); // 10. 返回ProductB1}
}// 10. 具體工廠A2
public class ConcreteFactoryA2 implements AbstractFactory {public ProductA createProductA() {return new ProductA2(); // 11. 返回ProductA2}public ProductB createProductB() {return new ProductB2(); // 12. 返回ProductB2}
}// 13. 客戶端代碼
public class Client {public static void main(String[] args) {AbstractFactory factory = new ConcreteFactoryA1(); // 14. 使用工廠A1ProductA productA = factory.createProductA(); // 15. 創建ProductAproductA.doSomething(); // 16. 輸出:ProductA1 does somethingProductB productB = factory.createProductB(); // 17. 創建ProductBproductB.doSomethingElse(); // 18. 輸出:ProductB1 does something else}
}
- 解釋:
AbstractFactory定義了兩個產品的創建方法,具體工廠實現不同產品的創建。
ConcreteFactoryA1和ConcreteFactoryA2根據需要創建一系列產品。
tips: Java中工廠模式和抽象工廠模式的區別
二、結構型設計模式
這些設計模式主要關注類和對象的組合,幫助我們設計靈活、易于擴展和維護的系統。
4. 適配器模式(Adapter Pattern)
- 定義:
適配器模式通過將一個類的接口轉換成客戶端期望的另一個接口,使得原本由于接口不兼容而不能一起工作的類可以一起工作。 - 應用場景:
用于將一個類的接口轉換為客戶期望的另一個接口,常見于第三方庫的集成時。 - 示例代碼:
// 1. 目標接口
public interface Target {void request();
}// 2. 適配者類,已經存在的接口
public class Adaptee {public void specificRequest() {System.out.println("Specific request");}
}// 3. 適配器類,實現目標接口,并委托調用適配者的方法
public class Adapter implements Target {private Adaptee adaptee;public Adapter(Adaptee adaptee) {this.adaptee = adaptee; // 4. 構造方法,傳入適配者}public void request() {adaptee.specificRequest(); // 5. 調用適配者的特定方法}
}// 6. 客戶端代碼
public class Client {public static void main(String[] args) {Adaptee adaptee = new Adaptee(); // 7. 創建適配者對象Target target = new Adapter(adaptee); // 8. 使用適配器target.request(); // 9. 輸出:Specific request}
}
- 解釋:
Target是客戶期望的接口,Adaptee是已經存在的接口,通過Adapter類適配兩者的差異。
5. 橋接模式(Bridge Pattern)
-
定義:
橋接模式通過將抽象部分和實現部分分離,使它們可以獨立變化。它主要用于接口和實現的解耦。 -
應用場景:
用于將抽象部分與實現部分分離,使它們可以獨立變化。常用于圖形繪制、設備控制等場景。 -
示例代碼:
// 1. 抽象類
public abstract class Shape {protected DrawingAPI drawingAPI; // 2. 依賴抽象的實現類public Shape(DrawingAPI drawingAPI) {this.drawingAPI = drawingAPI;}public abstract void draw(); // 3. 抽象方法
}// 4. 具體形狀類:Circle
public class Circle extends Shape {private double x, y, radius;public Circle(double x, double y, double radius, DrawingAPI drawingAPI) {super(drawingAPI); // 5. 調用父類構造器,傳入實現類this.x = x;this.y = y;this.radius = radius;}public void draw() {drawingAPI.drawCircle(x, y, radius); // 6. 委托給實現類}
}// 7. 抽象實現類
public interface DrawingAPI {void drawCircle(double x, double y, double radius); // 8. 繪制圓的方法
}// 9. 具體實現類:DrawingAPI1
public class DrawingAPI1 implements DrawingAPI {public void drawCircle(double x, double y, double radius) {System.out.println("Drawing Circle using DrawingAPI1 at (" + x + ", " + y + ") with radius " + radius);}
}// 10. 具體實現類:DrawingAPI2
public class DrawingAPI2 implements DrawingAPI {public void drawCircle(double x, double y, double radius) {System.out.println("Drawing Circle using DrawingAPI2 at (" + x + ", " + y + ") with radius " + radius);}
}// 11. 客戶端代碼
public class Client {public static void main(String[] args) {Shape shape1 = new Circle(1, 2, 3, new DrawingAPI1()); // 12. 使用API1shape1.draw(); // 13. 輸出:Drawing Circle using DrawingAPI1 at (1, 2) with radius 3Shape shape2 = new Circle(4, 5, 6, new DrawingAPI2()); // 14. 使用API2shape2.draw(); // 15. 輸出:Drawing Circle using DrawingAPI2 at (4, 5) with radius 6}
}
- 解釋:
Shape類定義了抽象的draw()方法,依賴于DrawingAPI接口。
Circle類實現了具體的圖形操作,將繪制行為委托給具體的實現類(DrawingAPI1或DrawingAPI2)。
三、行為型設計模式
6. 策略模式(Strategy Pattern)
-
定義:
策略模式定義了一系列算法,將每一個算法封裝起來,并使它們可以互換。它讓算法的變化獨立于使用算法的客戶。 -
應用場景:
策略模式用于定義一系列算法或策略,并允許在運行時切換策略。策略模式可以讓你避免使用大量的 if-else 或 switch 語句來處理不同的行為。 -
示例代碼:
假設你在開發一個支付系統,需要根據不同的支付方式(如支付寶、微信支付、信用卡支付)選擇不同的支付策略。
// 策略接口,定義支付行為
interface PaymentStrategy {void pay(int amount);
}// 具體策略:支付寶支付
class AlipayPayment implements PaymentStrategy {@Overridepublic void pay(int amount) {System.out.println("Using Alipay to pay " + amount + " units.");}
}// 具體策略:微信支付
class WeChatPayment implements PaymentStrategy {@Overridepublic void pay(int amount) {System.out.println("Using WeChat to pay " + amount + " units.");}
}// 具體策略:信用卡支付
class CreditCardPayment implements PaymentStrategy {@Overridepublic void pay(int amount) {System.out.println("Using Credit Card to pay " + amount + " units.");}
}// 上下文類,持有一個策略對象
class PaymentContext {private PaymentStrategy paymentStrategy;// 設置支付策略public void setPaymentStrategy(PaymentStrategy paymentStrategy) {this.paymentStrategy = paymentStrategy;}// 執行支付public void executePayment(int amount) {paymentStrategy.pay(amount);}
}// 客戶端代碼
public class StrategyPatternExample {public static void main(String[] args) {// 創建上下文對象PaymentContext paymentContext = new PaymentContext();// 設置支付寶支付策略paymentContext.setPaymentStrategy(new AlipayPayment());paymentContext.executePayment(100); // 輸出: Using Alipay to pay 100 units.// 設置微信支付策略paymentContext.setPaymentStrategy(new WeChatPayment());paymentContext.executePayment(200); // 輸出: Using WeChat to pay 200 units.// 設置信用卡支付策略paymentContext.setPaymentStrategy(new CreditCardPayment());paymentContext.executePayment(300); // 輸出: Using Credit Card to pay 300 units.}
}
- 解釋:
- PaymentStrategy 是一個策略接口,定義了支付方法。
- AlipayPayment、WeChatPayment、CreditCardPayment 是具體的支付策略,分別實現了 PaymentStrategy 接口。
- PaymentContext 類持有一個支付策略對象,并在運行時動態改變使用的支付策略。
- 在客戶端代碼中,使用不同的支付策略(支付寶、微信、信用卡)來執行支付。
7. 觀察者模式(Observer Pattern)
-
定義:
觀察者模式定義了對象間的一對多依賴關系,當一個對象的狀態發生改變時,所有依賴于它的對象都會自動更新。 -
應用場景:
觀察者模式用于一對多的場景,一個對象的狀態改變時,所有依賴于它的對象都會得到通知并自動更新。比如在實現事件監聽機制時,常常使用觀察者模式。 -
示例代碼:
假設你在開發一個天氣預報系統,當天氣變化時,所有的觀察者(如顯示板、手機應用等)都需要得到通知并更新天氣信息。
import java.util.ArrayList;
import java.util.List;// 觀察者接口,定義更新方法
interface Observer {void update(String weather);
}// 具體觀察者:顯示板
class DisplayBoard implements Observer {@Overridepublic void update(String weather) {System.out.println("DisplayBoard updated with weather: " + weather);}
}// 具體觀察者:手機應用
class MobileApp implements Observer {@Overridepublic void update(String weather) {System.out.println("MobileApp updated with weather: " + weather);}
}// 被觀察者:天氣數據
class WeatherData {private List<Observer> observers = new ArrayList<>();private String weather;// 添加觀察者public void addObserver(Observer observer) {observers.add(observer);}// 移除觀察者public void removeObserver(Observer observer) {observers.remove(observer);}// 設置天氣信息并通知所有觀察者public void setWeather(String weather) {this.weather = weather;notifyObservers();}// 通知所有觀察者更新private void notifyObservers() {for (Observer observer : observers) {observer.update(weather);}}
}// 客戶端代碼
public class ObserverPatternExample {public static void main(String[] args) {WeatherData weatherData = new WeatherData();// 創建觀察者DisplayBoard displayBoard = new DisplayBoard();MobileApp mobileApp = new MobileApp();// 添加觀察者weatherData.addObserver(displayBoard);weatherData.addObserver(mobileApp);// 改變天氣信息,通知所有觀察者weatherData.setWeather("Sunny"); // 輸出: DisplayBoard updated with weather: Sunny// 輸出: MobileApp updated with weather: Sunny// 修改天氣信息,觀察者會自動更新weatherData.setWeather("Rainy"); // 輸出: DisplayBoard updated with weather: Rainy// 輸出: MobileApp updated with weather: Rainy}
}
- 解釋:
- Observer 是觀察者接口,定義了 update 方法來接收通知。
- DisplayBoard 和 MobileApp 是具體的觀察者,分別實現了 Observer 接口。
- WeatherData 是被觀察者,保存了觀察者的列表,并在天氣變化時通知所有觀察者。
- 在客戶端代碼中,當天氣信息發生變化時,所有已注冊的觀察者都會接收到更新通知。
8. 命令模式(Command Pattern)
- 定義:
命令模式將請求封裝為對象,從而使用戶可以通過不同的請求對客戶端進行參數化。 - 應用場景:
命令模式將請求封裝成對象,從而使你可以用不同的請求、隊列和日志來參數化其他對象。它通常用于需要進行操作的場景,尤其是按鈕點擊、任務調度等。 - 示例代碼:
假設你在設計一個遙控器系統,每個按鈕上綁定不同的命令操作(如開燈、關燈)。
// 命令接口,定義執行操作的方法
interface Command {void execute();
}// 具體命令:開燈命令
class TurnOnLightCommand implements Command {private Light light;public TurnOnLightCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOn();}
}// 具體命令:關燈命令
class TurnOffLightCommand implements Command {private Light light;public TurnOffLightCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.turnOff();}
}// 接收者類:燈
class Light {public void turnOn() {System.out.println("The light is on.");}public void turnOff() {System.out.println("The light is off.");}
}// 調用者類:遙控器
class RemoteControl {private Command command;public void setCommand(Command command) {this.command = command;}public void pressButton() {command.execute();}
}// 客戶端代碼
public class CommandPatternExample {public static void main(String[] args) {Light light = new Light();Command turnOn = new TurnOnLightCommand(light);Command turnOff = new TurnOffLightCommand(light);RemoteControl remoteControl = new RemoteControl();// 按下開燈按鈕remoteControl.setCommand(turnOn);remoteControl.pressButton(); // 輸出: The light is on.// 按下關燈按鈕remoteControl.setCommand(turnOff);remoteControl.pressButton(); // 輸出: The light is off.}
}
- 解釋:
- Command 是命令接口,定義了 execute 方法來執行具體操作。
- TurnOnLightCommand 和 TurnOffLightCommand 是具體命令類,實現了 Command 接口,封裝了開燈和關燈操作。
- Light 是接收者類,實際執行開關燈操作。
- RemoteControl 是調用者類,接收命令并調用命令的 execute 方法。
9. 狀態模式(State Pattern)
-
定義:
狀態模式允許一個對象在其內部狀態發生改變時改變它的行為,看起來像是改變了其類。 -
應用場景:
狀態之間的轉換依賴于外部條件,常用于有限狀態機(例如游戲中的狀態機:開始、暫停、結束)。
10. 責任鏈模式(Chain of Responsibility Pattern)
-
定義:
責任鏈模式使得多個對象有機會處理請求,從而避免了請求的發送者和接收者之間的直接耦合。將請求沿著責任鏈傳遞,直到有一個對象處理它。 -
應用場景:
多個處理對象可能處理同一個請求時,比如日志過濾器、權限驗證等。
11. 中介者模式(Mediator Pattern)
-
定義:
中介者模式通過定義一個中介對象來封裝一組對象之間的交互,避免了對象間的直接引用,使得松耦合的設計變得更加容易。 -
應用場景:
多個類之間有復雜的交互時,使用中介者來集中管理這些交互,例如聊天室應用中的用戶之間的消息傳遞。
12. 備忘錄模式(Memento Pattern)
-
定義:
備忘錄模式允許在不暴露對象實現細節的情況下保存和恢復對象的內部狀態。 -
應用場景:
在需要保存對象歷史狀態的場景中,比如撤銷操作、保存游戲進度等。
13. 模板方法模式(Template Method Pattern)
-
定義:
模板方法模式定義了一個操作中的算法的骨架,將一些步驟的實現延遲到子類中。子類可以在不改變算法結構的情況下重新定義該算法的某些特定步驟。 -
應用場景:
一些固定的操作流程和步驟,但某些步驟需要子類提供具體實現時。
14. 訪問者模式(Visitor Pattern)
-
定義:
訪問者模式將數據結構和操作分開,使得可以在不修改數據結構的情況下添加新的操作。 -
應用場景:
對多個類操作進行擴展,但不想修改類的實現時,常用于編譯器、圖形結構等。
四、總結
這些行為型設計模式能夠讓你靈活地處理對象之間的交互,特別是在復雜系統中,能夠有效解耦和簡化代碼。