java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java高频设计模式

程序员必会的7种最常用高频设计模式

作者:神奇小汤圆

Java设计模式是提升代码质量的核心技能,这篇文章主要介绍了程序员必会的7种最常用高频设计模式,文中通过代码介绍的非常详细,需要的朋友可以参考下

前言

设计模式在我们的日常软件开发中无处不在。它们帮助我们编写更具可扩展性和可读性的代码。

今天,结合我的实际工作场景和源码示例,我将和你探讨工作中这 7 种最常用的设计模式,希望能对你有所帮助。

1. 单例模式

单例模式确保一个类只有一个实例,通常用于管理配置、缓存、线程池等共享资源。

代码实现 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;
    }
}

这是单例模式的标准写法,既保证了线程安全,又避免了性能损失。

代码解释:

代码实现 2:枚举单例模式

这是 Effective Java 中更推荐的单例模式实现方式。

public enum SingletonEnum {
    INSTANCE;

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

代码解释:

JDK 中的应用:

Spring 中的应用

默认情况下,Spring 的 Bean是单例模式。你可以通过使用 @Scope("prototype")将其更改为原型模式。

2. 工厂模式

工厂模式用于封装对象的创建逻辑,特别是在类实例化过程复杂时,可以降低耦合度**。

代码实现:简单工厂

以支付系统为例,不同的支付方式需要不同的对象。

// 抽象产品:交通工具 (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) {
        // 创建一辆汽车并驾驶
        Vehicle car = VehicleFactory.createVehicle("car");
        car.drive();

        // 创建一辆自行车并骑行
        Vehicle bicycle = VehicleFactory.createVehicle("bicycle");
        bicycle.drive();

        // 创建一辆卡车并驾驶
        Vehicle truck = VehicleFactory.createVehicle("truck");
        truck.drive();
    }
}

代码解释:

优点:

例如,如果你想添加 Motorcycle(摩托车)类型,可以这样做:

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

然后在 VehicleFactory中添加相应的逻辑:

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(); // 添加摩托车创建逻辑
            default:
                thrownew IllegalArgumentException("Invalid vehicle type: " + vehicleType);
        }
    }
}

这个例子展示了工厂模式如何通过工厂类将对象的创建和使用分离,使得代码更具可扩展性和可维护性,同时也方便了新产品类型的添加。

如果你想进一步避免在工厂类中使用 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) {
        // 创建一辆汽车并驾驶
        Vehicle car = VehicleFactory.createVehicle(Car.class);
        car.drive();

        // 创建一辆自行车并骑行
        Vehicle bicycle = VehicleFactory.createVehicle(Bicycle.class);
        bicycle.drive();

        // 创建一辆卡车并驾驶
        Vehicle truck = VehicleFactory.createVehicle(Truck.class);
        truck.drive();
    }
}

这种方法利用反射避免了繁琐的条件判断,提高了工厂的可扩展性。当添加新的交通工具类型时,无需修改工厂类代码。你只需要将新交通工具类的 Class对象传递给工厂类的 createVehicle()方法即可。

JDK 中的应用:

Spring 中的应用:

3. 建造者模式

建造者模式用于创建复杂对象,特别是当对象拥有多个可选参数时。

代码实现:组装一台电脑

// 产品类:电脑 (Computer)
class Computer {
    private String cpu;
    private String memory;
    private String storage;
    private String graphicsCard;
    private String operatingSystem;

    // 私有构造函数,只能通过 Builder 创建对象
    private Computer(Builder builder) {
        this.cpu = builder.cpu;
        this.memory = builder.memory;
        this.storage = builder.storage;
        this.graphicsCard = builder.graphicsCard;
        this.operatingSystem = builder.operatingSystem;
    }

     // 静态内部类 Builder
    publicstaticclass Builder {
        private String cpu;
        private String memory;
        private String storage;
        private String graphicsCard;
        private String operatingSystem;

        // 必填参数通过构造函数传递
        public Builder(String cpu, String memory) {
            this.cpu = cpu;
            this.memory = memory;
        }

        // 设置可选参数的方法
        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;
        }

        // 构建最终的 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) {
        // 使用建造者模式构建电脑
        Computer computer = new Computer.Builder("Intel i7", "16GB")
               .storage("1TB SSD")
               .graphicsCard("NVIDIA RTX 4060")
               .operatingSystem("Windows 10")
               .build();

        // 显示电脑配置信息
        computer.showConfiguration();
    }
}

JDK 中的应用:

Spring 中的应用:

4. 策略模式

策略模式将不同的算法封装成独立的类,并允许在运行时选择不同的策略。

代码实现:出行方式的选择

这次我们以出行方式的选择为例。不同的出行方式有不同的成本和速度,根据用户需求可以选择不同的出行策略:

// 策略接口:出行策略 (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) {
        // 假设步行速度为每小时 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) {
        // 假设自行车速度为每小时 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) {
        // 假设汽车每公里成本为 0.5 美元
        return distance * 0.5; 
    }

    @Override
    public double calculateTime(double distance) {
        // 假设汽车速度为每小时 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) {
        // 假设飞机每公里成本为 0.8 美元
        return distance * 0.8; 
    }

    @Override
    public double calculateTime(double distance) {
        // 假设飞机速度为每小时 800 公里
        return distance / 800.0; 
    }
}

// 上下文类:旅行规划者 (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; // 假设旅行距离为 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");
    }
}

代码解释:

优点:

这个例子可以帮助你更好地理解策略模式在实际场景中的应用。通过不同的策略实现不同的行为,并能根据用户需求灵活选择和切换策略,同时保持了代码的可扩展性和可维护性。

此外,策略模式通常与工厂模式结合使用,可以将策略对象的创建和使用分离,使代码更加灵活和易于维护。

JDK 中的应用:

Spring 中的应用:

5. 观察者模式

观察者模式定义了一种一对多的依赖关系。当一个对象的状态发生变化时,所有依赖于它的对象都会收到通知。

代码实现:股价更新系统

模拟当股价更新时通知投资者。

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

// 观察者接口
interface StockObserver {
    // 当股价更新时,此方法将被主题调用
    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() {
        // 遍历观察者列表,调用每个观察者的 update 方法进行通知
        for (StockObserver observer : observers) {
            observer.update(price);
        }
    }

    public void setPrice(double price) {
        // 设置新的股价并通知观察者
        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. 首先,创建一个 Stock对象作为主题。
  2. 创建多个 Investor对象作为观察者。
  3. 使用 registerObserver方法将这些投资者注册到 Stock对象。
  4. 当调用 setPrice方法更新股价时,所有注册的投资者会自动收到通知。
  5. 你可以使用 removeObserver方法移除不需要接收通知的投资者。

JDK 中的应用:

Spring 中的应用:

6. 代理模式

代理模式通过一个代理对象控制对目标对象的访问,常用于访问控制和日志记录等场景。此外,代理模式还包括静态代理和动态代理。

代码实现:静态代理

// 定义服务接口
interface Service {
    void execute();
}

// 实现服务接口的真实服务类
class RealService implements Service {
    @Override
    public void execute() {
        System.out.println("RealService is executing...");
    }
}

// 代理服务类,持有真实服务对象的引用
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");
    }
}


// 测试静态代理
publicclass StaticProxyExample {
    public static void main(String[] args) {
        Service service = new ServiceProxy();
        // 通过代理调用 execute 方法
        service.execute();
    }
}

代码解释:

代码实现:动态代理

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

// 定义服务接口
interface DynamicService {
    void performTask();
}

// 实现服务接口的真实服务类
class RealDynamicService implements DynamicService {
    @Override
    public void performTask() {
        System.out.println("RealDynamicService is performing a task...");
    }
}

// 动态代理调用处理器
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;
    }
}


// 测试动态代理
publicclass DynamicProxyExample {
    public static void main(String[] args) {
        RealDynamicService realService = new RealDynamicService();
        // 创建调用处理器并传入真实服务对象
        DynamicServiceInvocationHandler handler = new DynamicServiceInvocationHandler(realService);
        // 创建动态代理对象
        DynamicService proxyService = (DynamicService) Proxy.newProxyInstance(
                DynamicService.class.getClassLoader(),
                new Class<?>[]{DynamicService.class},
                handler);
        // 通过代理调用 performTask 方法
        proxyService.performTask();
    }
}

代码解释:

真实源码中的应用

在 Spring 框架中,AOP(面向切面编程)是代理模式的典型应用。Spring AOP 主要使用动态代理实现。当你使用 @Aspect注解定义一个切面,并使用 @Before@After@Around等注解定义通知时,Spring 会为受切面影响的 Bean 创建代理对象。

例如,你可能有一个服务类如下:

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...");
    }
}

代码解释:

Spring 使用动态代理机制(如果是接口则使用 JDK 动态代理,否则使用 CGLIB 动态代理),在不修改 UserService类代码的情况下,将切面逻辑织入到 UserService的方法调用中,从而实现了横切关注点的分离。

总结

7. 模板方法模式

模板方法模式定义了一个算法的骨架,并将具体实现留给子类。

代码实现:制作饮料

模拟制作咖啡和茶的过程。

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

    protected abstract void prepareIngredients();

    protected abstract void brew();

    // 将饮料倒入杯中,有具体实现,可以被重写
    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();
    }
}

代码解释:

这个例子更贴近实际生活。它通过制作饮料的过程展示了模板方法模式如何分离算法的框架和具体实现,提高了代码的复用性和可维护性。对于不同的饮料,我们只需要关注它们各自的特点,而不需要重复实现整个制作流程,体现了模板方法模式的优势。

通过使用模板方法模式,我们可以在保证流程一致性的同时,根据具体情况灵活定制不同的步骤,使得代码更加清晰、易于扩展和维护。

JDK 中的应用:

Spring 中的应用:

总结 

到此这篇关于程序员必会的7种最常用高频设计模式的文章就介绍到这了,更多相关Java高频设计模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文