最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

程序員必會的7種最常用高頻設(shè)計模式

 更新時間:2026年05月09日 11:29:30   作者:神奇小湯圓  
Java設(shè)計模式是提升代碼質(zhì)量的核心技能,這篇文章主要介紹了程序員必會的7種最常用高頻設(shè)計模式,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

前言

設(shè)計模式在我們的日常軟件開發(fā)中無處不在。它們幫助我們編寫更具可擴展性和可讀性的代碼。

今天,結(jié)合我的實際工作場景和源碼示例,我將和你探討工作中這 7 種最常用的設(shè)計模式,希望能對你有所幫助。

1. 單例模式

單例模式確保一個類只有一個實例,通常用于管理配置、緩存、線程池等共享資源。

代碼實現(xiàn) 1:雙重檢查鎖定

public class Singleton {
    privatestaticvolatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

這是單例模式的標(biāo)準(zhǔn)寫法,既保證了線程安全,又避免了性能損失。

代碼解釋:

  • private static volatile Singleton instance;
  • volatile關(guān)鍵字確保了 instance變量的可見性。當(dāng)一個線程修改了 instance的值,其他線程可以立即看到最新的值。
  • 同時,volatile還能防止指令重排序。在創(chuàng)建 Singleton實例時,new Singleton()操作并非原子操作。它包含三個步驟:分配內(nèi)存空間、初始化對象、將對象引用賦值給 instance。如果沒有 volatile,可能會發(fā)生指令重排序,導(dǎo)致其他線程獲取到一個尚未完全初始化的 instance對象。
  • private Singleton()
  • 私有構(gòu)造函數(shù)確保無法從外部直接實例化 Singleton類,保證了單例模式的唯一性。
  • public static Singleton getInstance()
  • 首先檢查 instance是否為 null。如果不為 null,直接返回實例,避免進入同步代碼塊,提高了性能。
  • 如果 instance為 null,進入同步代碼塊。synchronized (Singleton.class)語句鎖定 Singleton類,確保同一時間只有一個線程能進入創(chuàng)建實例的代碼塊。
  • 再次檢查 instance是否為 null。這是為了防止多個線程同時通過第一次檢查,進入同步代碼塊并重復(fù)創(chuàng)建實例。
  • 當(dāng) instance為 null時,執(zhí)行 instance = new Singleton();創(chuàng)建單例實例。

代碼實現(xiàn) 2:枚舉單例模式

這是 Effective Java 中更推薦的單例模式實現(xiàn)方式。

public enum SingletonEnum {
    INSTANCE;

    public void doSomething() {
        System.out.println("This is a singleton instance doing something.");
    }
}

代碼解釋:

  • 枚舉類型是 Java 中一種特殊的類。它保證了實例的唯一性,并且天生是線程安全的。
  • INSTANCE是 SingletonEnum枚舉的唯一實例。你可以通過 SingletonEnum.INSTANCE獲取該單例。
  • 你可以在枚舉中添加自定義方法,如 doSomething(),來實現(xiàn)單例需要完成的業(yè)務(wù)邏輯。
  • 枚舉單例可以防止反射和序列化破壞單例,因為 Java 規(guī)范保證了枚舉類型的實例化是唯一的,且在序列化和反序列化過程中不會創(chuàng)建新實例。

JDK 中的應(yīng)用:

  • java.lang.Runtime.getRuntime()
  • java.util.logging.Logger

Spring 中的應(yīng)用

默認情況下,Spring 的 Bean是單例模式。你可以通過使用 @Scope("prototype")將其更改為原型模式。

2. 工廠模式

工廠模式用于封裝對象的創(chuàng)建邏輯,特別是在類實例化過程復(fù)雜時,可以降低耦合度**。

代碼實現(xiàn):簡單工廠

以支付系統(tǒng)為例,不同的支付方式需要不同的對象。

// 抽象產(chǎn)品:交通工具 (Vehicle)
abstractclass Vehicle {
    public abstract void drive();
}

class Car extends Vehicle {
    @Override
    public void drive() {
        System.out.println("Driving a car.");
    }
}

class Bicycle extends Vehicle {
    @Override
    public void drive() {
        System.out.println("Riding a bicycle.");
    }
}

class Truck extends Vehicle {
    @Override
    public void drive() {
        System.out.println("Driving a truck.");
    }
}

// 工廠類:交通工具工廠 (Vehicle factories)
class VehicleFactory {
    public static Vehicle createVehicle(String vehicleType) {
        switch (vehicleType) {
            case"car":
                returnnew Car();
            case"bicycle":
                returnnew Bicycle();
            case"truck":
                returnnew Truck();
            default:
                thrownew IllegalArgumentException("Invalid vehicle type: " + vehicleType);
        }
    }
}

// 測試類
publicclass FactoryPatternExample {
    public static void main(String[] args) {
        // 創(chuàng)建一輛汽車并駕駛
        Vehicle car = VehicleFactory.createVehicle("car");
        car.drive();

        // 創(chuàng)建一輛自行車并騎行
        Vehicle bicycle = VehicleFactory.createVehicle("bicycle");
        bicycle.drive();

        // 創(chuàng)建一輛卡車并駕駛
        Vehicle truck = VehicleFactory.createVehicle("truck");
        truck.drive();
    }
}

代碼解釋:

  • 當(dāng)你需要制造交通工具時,不需要直接調(diào)用 CarBicycle或 Truck的構(gòu)造函數(shù),而是調(diào)用 VehicleFactory.createVehicle()方法,并傳入你想要制造的交通工具類型。
  • 工廠會根據(jù)你提供的類型創(chuàng)建并返回相應(yīng)的交通工具實例。
  • 你可以通過調(diào)用 drive()方法來使用制造出來的交通工具。

優(yōu)點:

  • 代碼解耦:交通工具的創(chuàng)建邏輯和使用邏輯分離。用戶不需要關(guān)心具體的交通工具創(chuàng)建過程,只需要告訴工廠想要什么類型的交通工具。
  • 易于擴展:如果你想添加新的交通工具類型,只需創(chuàng)建一個新的具體交通工具類并繼承 Vehicle,然后在 VehicleFactory的 createVehicle()方法中添加相應(yīng)的創(chuàng)建邏輯即可。

例如,如果你想添加 Motorcycle(摩托車)類型,可以這樣做:

class Motorcycle extends Vehicle {
    @Override
    public void drive() {
        System.out.println("Riding a motorcycle.");
    }
}

然后在 VehicleFactory中添加相應(yīng)的邏輯:

class VehicleFactory {
    public static Vehicle createVehicle(String vehicleType) {
        switch (vehicleType) {
            case"car":
                returnnew Car();
            case"bicycle":
                returnnew Bicycle();
            case"truck":
                returnnew Truck();
            case"motorcycle":
                returnnew Motorcycle(); // 添加摩托車創(chuàng)建邏輯
            default:
                thrownew IllegalArgumentException("Invalid vehicle type: " + vehicleType);
        }
    }
}

這個例子展示了工廠模式如何通過工廠類將對象的創(chuàng)建和使用分離,使得代碼更具可擴展性和可維護性,同時也方便了新產(chǎn)品類型的添加。

如果你想進一步避免在工廠類中使用 switch if-else 語句,可以使用反射機制如下:

class VehicleFactory {
    public static Vehicle createVehicle(Class<? extends Vehicle> vehicleClass) {
        try {
            Constructor<? extends Vehicle> constructor = vehicleClass.getDeclaredConstructor();
            return constructor.newInstance();
        } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
            thrownew RuntimeException("Failed to create vehicle: " + e.getMessage());
        }
    }
}

publicclass FactoryPatternExample {
    public static void main(String[] args) {
        // 創(chuàng)建一輛汽車并駕駛
        Vehicle car = VehicleFactory.createVehicle(Car.class);
        car.drive();

        // 創(chuàng)建一輛自行車并騎行
        Vehicle bicycle = VehicleFactory.createVehicle(Bicycle.class);
        bicycle.drive();

        // 創(chuàng)建一輛卡車并駕駛
        Vehicle truck = VehicleFactory.createVehicle(Truck.class);
        truck.drive();
    }
}

這種方法利用反射避免了繁瑣的條件判斷,提高了工廠的可擴展性。當(dāng)添加新的交通工具類型時,無需修改工廠類代碼。你只需要將新交通工具類的 Class對象傳遞給工廠類的 createVehicle()方法即可。

JDK 中的應(yīng)用:

  • java.util.Calendar.getInstance()
  • javax.xml.parsers.DocumentBuilderFactory.newInstance()

Spring 中的應(yīng)用:

  • BeanFactory和 ApplicationContext都是工廠模式的體現(xiàn)。

3. 建造者模式

建造者模式用于創(chuàng)建復(fù)雜對象,特別是當(dāng)對象擁有多個可選參數(shù)時。

代碼實現(xiàn):組裝一臺電腦

// 產(chǎn)品類:電腦 (Computer)
class Computer {
    private String cpu;
    private String memory;
    private String storage;
    private String graphicsCard;
    private String operatingSystem;

    // 私有構(gòu)造函數(shù),只能通過 Builder 創(chuàng)建對象
    private Computer(Builder builder) {
        this.cpu = builder.cpu;
        this.memory = builder.memory;
        this.storage = builder.storage;
        this.graphicsCard = builder.graphicsCard;
        this.operatingSystem = builder.operatingSystem;
    }

     // 靜態(tài)內(nèi)部類 Builder
    publicstaticclass Builder {
        private String cpu;
        private String memory;
        private String storage;
        private String graphicsCard;
        private String operatingSystem;

        // 必填參數(shù)通過構(gòu)造函數(shù)傳遞
        public Builder(String cpu, String memory) {
            this.cpu = cpu;
            this.memory = memory;
        }

        // 設(shè)置可選參數(shù)的方法
        public Builder storage(String storage) {
            this.storage = storage;
            returnthis;
        }

        public Builder graphicsCard(String graphicsCard) {
            this.graphicsCard = graphicsCard;
            returnthis;
        }

        public Builder operatingSystem(String operatingSystem) {
            this.operatingSystem = operatingSystem;
            returnthis;
        }

        // 構(gòu)建最終的 Computer 對象
        public Computer build() {
            returnnew Computer(this);
        }
    }

    // 顯示電腦配置信息
    public void showConfiguration() {
        System.out.println("CPU: " + cpu);
        System.out.println("Memory: " + memory);
        System.out.println("Storage: " + storage);
        System.out.println("Graphics Card: " + graphicsCard);
        System.out.println("Operating System: " + operatingSystem);
    }
}

// 測試類
publicclass BuilderPatternExample {
    public static void main(String[] args) {
        // 使用建造者模式構(gòu)建電腦
        Computer computer = new Computer.Builder("Intel i7", "16GB")
               .storage("1TB SSD")
               .graphicsCard("NVIDIA RTX 4060")
               .operatingSystem("Windows 10")
               .build();

        // 顯示電腦配置信息
        computer.showConfiguration();
    }
}

JDK 中的應(yīng)用:

  • StringBuilder
  • Stream.Builder

Spring 中的應(yīng)用:

  • BeanDefinitionBuilder用于構(gòu)建 BeanDefinition對象,這是 Spring 容器管理 Bean 的核心組件。
  • UriComponentsBuilder用于構(gòu)建 URI。

4. 策略模式

策略模式將不同的算法封裝成獨立的類,并允許在運行時選擇不同的策略。

代碼實現(xiàn):出行方式的選擇

這次我們以出行方式的選擇為例。不同的出行方式有不同的成本和速度,根據(jù)用戶需求可以選擇不同的出行策略:

// 策略接口:出行策略 (Travel Strategy)
interface TravelStrategy {
    void travel();
    double calculateCost(double distance);
    double calculateTime(double distance);
}

// 具體策略:步行 (Walk)
class WalkStrategy implements TravelStrategy {
    @Override
    public void travel() {
        System.out.println("Choose to travel on foot.");
    }

    @Override
    public double calculateCost(double distance) {
        // 步行通常沒有成本
        return0.0; 
    }

    @Override
    public double calculateTime(double distance) {
        // 假設(shè)步行速度為每小時 5 公里
        return distance / 5.0; 
    }
}

// 具體策略:自行車 (Bike)
class BikeStrategy implements TravelStrategy {
    @Override
    public void travel() {
        // 選擇騎自行車出行
        System.out.println("Choose to travel by bike.");
    }

    @Override
    public double calculateCost(double distance) {
        // 自行車通常沒有成本
        return0.0; 
    }

    @Override
    public double calculateTime(double distance) {
        // 假設(shè)自行車速度為每小時 15 公里
        return distance / 15.0; 
    }
}

// 具體策略:汽車 (Car)
class CarStrategy implements TravelStrategy {
    @Override
    public void travel() {
        System.out.println("Choose to travel by car.");
    }

    @Override
    public double calculateCost(double distance) {
        // 假設(shè)汽車每公里成本為 0.5 美元
        return distance * 0.5; 
    }

    @Override
    public double calculateTime(double distance) {
        // 假設(shè)汽車速度為每小時 60 公里
        return distance / 60.0; 
    }
}

// 具體策略:飛機 (Airplane)
class AirplaneStrategy implements TravelStrategy {
    @Override
    public void travel() {
        System.out.println("Choose to travel by airplane.");
    }

    @Override
    public double calculateCost(double distance) {
        // 假設(shè)飛機每公里成本為 0.8 美元
        return distance * 0.8; 
    }

    @Override
    public double calculateTime(double distance) {
        // 假設(shè)飛機速度為每小時 800 公里
        return distance / 800.0; 
    }
}

// 上下文類:旅行規(guī)劃者 (Travel Planner)
class TravelPlanner {
    private TravelStrategy travelStrategy;

    public TravelPlanner(TravelStrategy travelStrategy) {
        this.travelStrategy = travelStrategy;
    }

    public void setTravelStrategy(TravelStrategy travelStrategy) {
        this.travelStrategy = travelStrategy;
    }

    public void planTravel() {
        travelStrategy.travel();
    }

    public double calculateCost(double distance) {
        return travelStrategy.calculateCost(distance);
    }

    public double calculateTime(double distance) {
        return travelStrategy.calculateTime(distance);
    }
}

// 測試類
publicclass StrategyPatternExample {
    public static void main(String[] args) {
        double distance = 100.0; // 假設(shè)旅行距離為 100 公里

        // 步行出行
        TravelPlanner travelPlanner1 = new TravelPlanner(new WalkStrategy());
        travelPlanner1.planTravel();
        System.out.println("Cost: " + travelPlanner1.calculateCost(distance) + " dollars");
        System.out.println("Time: " + travelPlanner1.calculateTime(distance) + " hours");

        // 騎自行車出行
        TravelPlanner travelPlanner2 = new TravelPlanner(new BikeStrategy());
        travelPlanner2.planTravel();
        System.out.println("Cost: " + travelPlanner2.calculateCost(distance) + " dollars");
        System.out.println("Time: " + travelPlanner2.calculateTime(distance) + " hours");

        // 開車出行
        TravelPlanner travelPlanner3 = new TravelPlanner(new CarStrategy());
        travelPlanner3.planTravel();
        System.out.println("Cost: " + travelPlanner3.calculateCost(distance) + " dollars");
        System.out.println("Time: " + travelPlanner3.calculateTime(distance) + " hours");

        // 乘飛機出行
        TravelPlanner travelPlanner4 = new TravelPlanner(new AirplaneStrategy());
        travelPlanner4.planTravel();
        System.out.println("Cost: " + travelPlanner4.calculateCost(distance) + " dollars");
        System.out.println("Time: " + travelPlanner4.calculateTime(distance) + " hours");
    }
}

代碼解釋:

  • 首先,通過實現(xiàn) TravelStrategy接口定義了不同的出行策略。
  • 然后,創(chuàng)建 TravelPlanner對象,并根據(jù)需要選擇不同的出行策略。
  • 最后,調(diào)用 planTravel()方法執(zhí)行出行操作,并使用 calculateCost()和 calculateTime()方法計算成本和時間。

優(yōu)點:

  • 易于擴展:如果你想添加新的出行方式,只需創(chuàng)建一個新的 TravelStrategy實現(xiàn)類,無需修改 TravelPlanner類的代碼。
  • 靈活切換:你可以輕松地在不同出行策略之間切換,以滿足不同的出行需求。
  • 代碼清晰:不同出行方式的邏輯被封裝在各自的策略類中,使得代碼更具可讀性和可維護性。

這個例子可以幫助你更好地理解策略模式在實際場景中的應(yīng)用。通過不同的策略實現(xiàn)不同的行為,并能根據(jù)用戶需求靈活選擇和切換策略,同時保持了代碼的可擴展性和可維護性。

此外,策略模式通常與工廠模式結(jié)合使用,可以將策略對象的創(chuàng)建和使用分離,使代碼更加靈活和易于維護。

JDK 中的應(yīng)用:

  • java.util.Comparator是一個典型的策略模式。

Spring 中的應(yīng)用:

  • 事務(wù)管理 (TransactionManager),支持編程式和聲明式事務(wù)。

5. 觀察者模式

觀察者模式定義了一種一對多的依賴關(guān)系。當(dāng)一個對象的狀態(tài)發(fā)生變化時,所有依賴于它的對象都會收到通知。

代碼實現(xiàn):股價更新系統(tǒng)

模擬當(dāng)股價更新時通知投資者。

import java.util.ArrayList;
import java.util.List;

// 觀察者接口
interface StockObserver {
    // 當(dāng)股價更新時,此方法將被主題調(diào)用
    void update(double price); 
}

// 具體觀察者:投資者 (Investor)
class Investor implements StockObserver {
    private String name;

    public Investor(String name) {
        this.name = name;
    }

    @Override
    public void update(double price) {
        // 打印投資者的名字和接收到的股價更新信息
        System.out.println(name + " received an update: The current stock price is " + price); 
    }
}

// 主題接口 (Subject interface)
interface StockSubject {
    // 注冊觀察者
    void registerObserver(StockObserver observer); 
    // 移除觀察者
    void removeObserver(StockObserver observer); 
    // 通知所有注冊的觀察者
    void notifyObservers(); 
}

// 具體主題:股票 (Stock)
class Stock implements StockSubject {
    private List<StockObserver> observers = new ArrayList<>();
    privatedouble price;

    @Override
    public void registerObserver(StockObserver observer) {
        // 將觀察者添加到觀察者列表
        observers.add(observer); 
    }

    @Override
    public void removeObserver(StockObserver observer) {
        // 從觀察者列表中移除觀察者
        observers.remove(observer); 
    }

    @Override
    public void notifyObservers() {
        // 遍歷觀察者列表,調(diào)用每個觀察者的 update 方法進行通知
        for (StockObserver observer : observers) {
            observer.update(price);
        }
    }

    public void setPrice(double price) {
        // 設(shè)置新的股價并通知觀察者
        this.price = price; 
        notifyObservers();
    }
}

// 測試類
publicclass ObserverPatternExample {
    public static void main(String[] args) {
        Stock stock = new Stock();

        Investor investor1 = new Investor("Alice");
        Investor investor2 = new Investor("Bob");
        Investor investor3 = new Investor("Charlie");

        // 注冊投資者為觀察者
        stock.registerObserver(investor1);
        stock.registerObserver(investor2);
        stock.registerObserver(investor3);

        // 更新股價,觀察者將收到通知
        stock.setPrice(100.0); 
        stock.setPrice(105.0);

        // 移除一個觀察者
        stock.removeObserver(investor2); 

        // 再次更新股價,剩余的觀察者將收到通知
        stock.setPrice(110.0); 
    }
}

輸出:

Alice received an update: The current stock price is 100.0
Bob received an update: The current stock price is 100.0
Charlie received an update: The current stock price is 100.0
Alice received an update: The current stock price is 105.0
Bob received an update: The current stock price is 105.0
Charlie received an update: The current stock price is 105.0
Alice received an update: The current stock price is 110.0
Charlie received an update: The current stock price is 110.0

代碼解釋:

  1. 首先,創(chuàng)建一個 Stock對象作為主題。
  2. 創(chuàng)建多個 Investor對象作為觀察者。
  3. 使用 registerObserver方法將這些投資者注冊到 Stock對象。
  4. 當(dāng)調(diào)用 setPrice方法更新股價時,所有注冊的投資者會自動收到通知。
  5. 你可以使用 removeObserver方法移除不需要接收通知的投資者。

JDK 中的應(yīng)用:

  • java.util.Observer和 java.util.Observable
  • javax.swing.event.ChangeListener

Spring 中的應(yīng)用:

  • ApplicationEvent和 ApplicationListener是典型的實現(xiàn)。

6. 代理模式

代理模式通過一個代理對象控制對目標(biāo)對象的訪問,常用于訪問控制和日志記錄等場景。此外,代理模式還包括靜態(tài)代理和動態(tài)代理。

代碼實現(xiàn):靜態(tài)代理

// 定義服務(wù)接口
interface Service {
    void execute();
}

// 實現(xiàn)服務(wù)接口的真實服務(wù)類
class RealService implements Service {
    @Override
    public void execute() {
        System.out.println("RealService is executing...");
    }
}

// 代理服務(wù)類,持有真實服務(wù)對象的引用
class ServiceProxy implements Service {
    private Service realService;

    public ServiceProxy() {
        this.realService = new RealService();
    }

    @Override
    public void execute() {
        System.out.println("Additional operations before calling the real service, such as logging or permission checking");
        realService.execute();
        System.out.println("Additional operations after calling the real service, such as performance statistics");
    }
}


// 測試靜態(tài)代理
publicclass StaticProxyExample {
    public static void main(String[] args) {
        Service service = new ServiceProxy();
        // 通過代理調(diào)用 execute 方法
        service.execute();
    }
}

代碼解釋:

  • Service接口:定義了服務(wù)的抽象方法 execute。
  • RealService類:它是實現(xiàn) Service接口的具體類,提供了服務(wù)的具體實現(xiàn)。
  • ServiceProxy類:它是 RealService的代理類,也實現(xiàn)了 Service接口。在 execute方法中,除了調(diào)用真實服務(wù)的 execute方法外,還添加了前后額外的操作,實現(xiàn)了代理功能。
  • 在 StaticProxyExample的 main方法中,創(chuàng)建一個 ServiceProxy對象并調(diào)用 execute方法,實現(xiàn)了對 RealService的代理調(diào)用。

代碼實現(xiàn):動態(tài)代理

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 定義服務(wù)接口
interface DynamicService {
    void performTask();
}

// 實現(xiàn)服務(wù)接口的真實服務(wù)類
class RealDynamicService implements DynamicService {
    @Override
    public void performTask() {
        System.out.println("RealDynamicService is performing a task...");
    }
}

// 動態(tài)代理調(diào)用處理器
class DynamicServiceInvocationHandler implements InvocationHandler {
    private Object target;

    public DynamicServiceInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Additional operations before calling the real service, such as logging or permission checking.");
        Object result = method.invoke(target, args);
        System.out.println("Additional operations after calling the real service, such as performance statistics.");
        return result;
    }
}


// 測試動態(tài)代理
publicclass DynamicProxyExample {
    public static void main(String[] args) {
        RealDynamicService realService = new RealDynamicService();
        // 創(chuàng)建調(diào)用處理器并傳入真實服務(wù)對象
        DynamicServiceInvocationHandler handler = new DynamicServiceInvocationHandler(realService);
        // 創(chuàng)建動態(tài)代理對象
        DynamicService proxyService = (DynamicService) Proxy.newProxyInstance(
                DynamicService.class.getClassLoader(),
                new Class<?>[]{DynamicService.class},
                handler);
        // 通過代理調(diào)用 performTask 方法
        proxyService.performTask();
    }
}

代碼解釋:

  • DynamicService接口:定義了服務(wù)的抽象方法 performTask。
  • RealDynamicService類:它是實現(xiàn) DynamicService接口的具體類,提供了服務(wù)的具體實現(xiàn)。
  • DynamicServiceInvocationHandler類:實現(xiàn)了 InvocationHandler接口,當(dāng)代理對象的方法被調(diào)用時,其 invoke方法會被觸發(fā)。在 invoke方法中,在調(diào)用真實服務(wù)方法前后添加了額外操作。
  • 在 DynamicProxyExample的 main方法中,首先創(chuàng)建 RealDynamicService的實例,然后創(chuàng)建 DynamicServiceInvocationHandler實例并傳入真實服務(wù)對象。接著使用 Proxy.newProxyInstance方法創(chuàng)建 DynamicService的代理對象,并調(diào)用 performTask方法,從而實現(xiàn)動態(tài)代理。

真實源碼中的應(yīng)用

在 Spring 框架中,AOP(面向切面編程)是代理模式的典型應(yīng)用。Spring AOP 主要使用動態(tài)代理實現(xiàn)。當(dāng)你使用 @Aspect注解定義一個切面,并使用 @Before、@After、@Around等注解定義通知時,Spring 會為受切面影響的 Bean 創(chuàng)建代理對象。

例如,你可能有一個服務(wù)類如下:

import org.springframework.stereotype.Service;

@Service
public class UserService {
    public void addUser(String username) {
        System.out.println("Adding user: " + username);
    }
}

你可以定義一個切面類如下:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class UserServiceAspect {
    @Before("execution(* com.example.service.UserService.addUser(..))")
    public void beforeAddUser() {
        System.out.println("Before adding user...");
    }
}

代碼解釋:

  • UserService是一個普通的服務(wù)類,包含 addUser方法。
  • UserServiceAspect是一個切面類,使用 @Before注解定義了一個前置通知。當(dāng) UserService的 addUser方法被調(diào)用時,Spring 會為 UserService創(chuàng)建一個代理對象,并在調(diào)用 addUser方法之前執(zhí)行 beforeAddUser方法。

Spring 使用動態(tài)代理機制(如果是接口則使用 JDK 動態(tài)代理,否則使用 CGLIB 動態(tài)代理),在不修改 UserService類代碼的情況下,將切面邏輯織入到 UserService的方法調(diào)用中,從而實現(xiàn)了橫切關(guān)注點的分離。

總結(jié)

  • 靜態(tài)代理在編譯時確定代理類和被代理類的關(guān)系,代碼簡單易懂,但如果接口方法較多,為每個方法添加代理邏輯會很繁瑣。
  • 動態(tài)代理通過反射機制在運行時生成代理對象,更加靈活,可以動態(tài)添加代理邏輯。適用于需要為多個不同的類或方法添加相同或相似代理邏輯的場景,如日志記錄、性能統(tǒng)計、權(quán)限檢查等。
  • Spring AOP 是動態(tài)代理在實際框架中的應(yīng)用,它幫助開發(fā)者更好地實現(xiàn)面向切面編程,將橫切關(guān)注點(如日志、事務(wù)、安全等)與業(yè)務(wù)邏輯分離,提高了代碼的可維護性和可擴展性。

7. 模板方法模式

模板方法模式定義了一個算法的骨架,并將具體實現(xiàn)留給子類。

代碼實現(xiàn):制作飲料

模擬制作咖啡和茶的過程。

abstract class BeverageMaker {
    // 模板方法,定義制作飲料的算法骨架
    public final void makeBeverage() {
        prepareIngredients();
        brew();
        pourInCup();
        addCondiments();
    }

    protected abstract void prepareIngredients();

    protected abstract void brew();

    // 將飲料倒入杯中,有具體實現(xiàn),可以被重寫
    protected void pourInCup() {
        System.out.println("Pour the beverage into a cup");
    }

    protected abstract void addCondiments();
}

// 具體子類 CoffeeMaker,用于制作咖啡
class CoffeeMaker extends BeverageMaker {
    @Override
    protected void prepareIngredients() {
        System.out.println("Prepare coffee beans and water");
    }

    @Override
    protected void brew() {
        System.out.println("Brew coffee with a coffee machine");
    }

    @Override
    protected void addCondiments() {
        System.out.println("Add sugar and milk");
    }
}

// 具體子類 TeaMaker,用于制作茶
class TeaMaker extends BeverageMaker {
    @Override
    protected void prepareIngredients() {
        System.out.println("Prepare tea leaves and hot water");
    }

    @Override
    protected void brew() {
        System.out.println("Brew tea with hot water");
    }

    @Override
    protected void addCondiments() {
        System.out.println("Add lemon slices");
    }
}

// 測試類
publicclass TemplateMethodPatternDemo {
    public static void main(String[] args) {
        BeverageMaker coffeeMaker = new CoffeeMaker();
        System.out.println("Making coffee:");
        coffeeMaker.makeBeverage();

        System.out.println("\n-----------------");

        BeverageMaker teaMaker = new TeaMaker();
        System.out.println("Making tea:");
        teaMaker.makeBeverage();
    }
}

代碼解釋:

  • BeverageMaker是一個抽象類,其中 makeBeverage是一個模板方法。它定義了制作飲料的算法骨架,即先準(zhǔn)備原料,然后沖泡,接著將飲料倒入杯中,最后添加調(diào)料。該方法是 final的,不允許子類修改這個流程的順序。
  • prepareIngredients、brew和 addCondiments是抽象方法。因為不同的飲料準(zhǔn)備原料、沖泡和添加調(diào)料的方式不同,所以這些方法由具體的子類來實現(xiàn)。
  • pourInCup方法是一個有默認實現(xiàn)的方法。對于大多數(shù)飲料來說,將飲料倒入杯中的操作是相似的,但如果子類有特殊需求,也可以重寫該方法。
  • CoffeeMaker和 TeaMaker是 BeverageMaker的具體子類。它們分別重寫了 prepareIngredients、brew和 addCondiments方法,實現(xiàn)了制作咖啡和茶的具體步驟。
  • 在 TemplateMethodPatternDemo的 main方法中,我們創(chuàng)建了 CoffeeMaker和 TeaMaker的實例,并調(diào)用它們的 makeBeverage方法。這樣,我們可以看到,在不改變整體制作流程的情況下,不同的飲料可以按照自己的特點完成各個步驟。

這個例子更貼近實際生活。它通過制作飲料的過程展示了模板方法模式如何分離算法的框架和具體實現(xiàn),提高了代碼的復(fù)用性和可維護性。對于不同的飲料,我們只需要關(guān)注它們各自的特點,而不需要重復(fù)實現(xiàn)整個制作流程,體現(xiàn)了模板方法模式的優(yōu)勢。

通過使用模板方法模式,我們可以在保證流程一致性的同時,根據(jù)具體情況靈活定制不同的步驟,使得代碼更加清晰、易于擴展和維護。

JDK 中的應(yīng)用:

  • java.util.AbstractList和 java.util.AbstractMap

Spring 中的應(yīng)用:

  • JdbcTemplate和 RestTemplate

總結(jié) 

到此這篇關(guān)于程序員必會的7種最常用高頻設(shè)計模式的文章就介紹到這了,更多相關(guān)Java高頻設(shè)計模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java隨機生成一個名字和對應(yīng)拼音的方法

    java隨機生成一個名字和對應(yīng)拼音的方法

    這篇文章主要介紹了java隨機生成一個名字和對應(yīng)拼音的方法,涉及java針對數(shù)組及隨機數(shù)操作的相關(guān)技巧,需要的朋友可以參考下
    2015-07-07
  • VSCode?Java項目JDK配置完整攻略指南(JDK版本切換不求人)

    VSCode?Java項目JDK配置完整攻略指南(JDK版本切換不求人)

    JDK是指Java軟件開發(fā)工具包,是Java編程語言的官方實現(xiàn),由Oracle公司提供,不斷更新和維護,這篇文章主要介紹了VSCode Java項目JDK配置(JDK版本切換不求人)的相關(guān)資料,需要的朋友可以參考下
    2026-05-05
  • Java實現(xiàn)公眾號功能、關(guān)注及消息推送實例代碼

    Java實現(xiàn)公眾號功能、關(guān)注及消息推送實例代碼

    公眾號開發(fā)近些年是一個比較熱門的方向,下面這篇文章主要給大家介紹了關(guān)于Java實現(xiàn)公眾號功能、關(guān)注及消息推送的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2023-11-11
  • java如何獲取兩個List集合之間的交集、差集、并集

    java如何獲取兩個List集合之間的交集、差集、并集

    在日常開發(fā)中經(jīng)常會遇到對2個集合的操作,例如2個集合之間取相同的元素(交集),2個集合之間取不相同的元素(差集)等等,這篇文章主要給大家介紹了關(guān)于java如何獲取兩個List集合之間的交集、差集、并集的相關(guān)資料,需要的朋友可以參考下
    2024-02-02
  • Spring Boot 日志級別及配置詳解

    Spring Boot 日志級別及配置詳解

    本文講解SpringBoot日志核心:通過slf4j記錄日志,支持多級別(INFO/DEBUG/TRACE)及配置輸出格式、路徑、分割策略,便于問題定位和數(shù)據(jù)分析,同時結(jié)合Lombok簡化日志代碼,強調(diào)日志持久化與安全審計的重要性,感興趣的朋友一起看看吧
    2025-07-07
  • Spring Boot中的屬性綁定的實現(xiàn)

    Spring Boot中的屬性綁定的實現(xiàn)

    這篇文章主要介紹了Spring Boot中的屬性綁定的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 比較排序之冒泡排序的實現(xiàn)

    比較排序之冒泡排序的實現(xiàn)

    下面小編就為大家?guī)硪黄容^排序之冒泡排序的小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧實現(xiàn)。
    2017-06-06
  • 使用Spring來創(chuàng)建一個簡單的工作流引擎

    使用Spring來創(chuàng)建一個簡單的工作流引擎

    這篇文章主要給大家介紹了關(guān)于使用Spring來創(chuàng)建一個簡單的工作流引擎的相關(guān)資料,需要的朋友可以參考下
    2006-12-12
  • JDK1.6“新“特性Instrumentation之JavaAgent(推薦)

    JDK1.6“新“特性Instrumentation之JavaAgent(推薦)

    這篇文章主要介紹了JDK1.6“新“特性Instrumentation之JavaAgent,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • java實現(xiàn)的日期時間轉(zhuǎn)換工具類完整示例

    java實現(xiàn)的日期時間轉(zhuǎn)換工具類完整示例

    這篇文章主要介紹了java實現(xiàn)的日期時間轉(zhuǎn)換工具類,結(jié)合完整實例形式分析了java針對日期時間常見的轉(zhuǎn)換、計算、格式化等相關(guān)操作與封裝技巧,需要的朋友可以參考下
    2019-10-10

最新評論

金塔县| 平山县| 洛宁县| 彩票| 会同县| 读书| 宣武区| 无棣县| 高台县| 弥渡县| 垣曲县| 灵石县| 黄骅市| 阿拉善右旗| 丰城市| 醴陵市| 卢湾区| 垣曲县| 北票市| 溧水县| 平定县| 宣武区| 靖边县| 临泽县| 邹城市| 宁国市| 兰坪| 华亭县| 凤台县| 铁岭市| 仪陇县| 三台县| 德清县| 通化县| 修文县| 咸宁市| 淮南市| 上思县| 屏东市| 陆川县| 达日县|