2026/5/19 0:57:31
网站建设
项目流程
wordpress网址打不开,做网站优化的关键词怎么设置,网站建设网站制作价格,官网浏览器设计模式在我们的日常软件开发中无处不在。它们帮助我们编写更具可扩展性和可读性的代码。
今天#xff0c;结合我的实际工作场景和源码示例#xff0c;我将和你探讨工作中这 7 种最常用的设计模式#xff0c;希望能对你有所帮助。
1. 单例模式
单例模式确保一个类只有一…设计模式在我们的日常软件开发中无处不在。它们帮助我们编写更具可扩展性和可读性的代码。今天结合我的实际工作场景和源码示例我将和你探讨工作中这 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; } }这是单例模式的标准写法既保证了线程安全又避免了性能损失。代码解释private static volatile Singleton instance;volatile关键字确保了instance变量的可见性。当一个线程修改了instance的值其他线程可以立即看到最新的值。同时volatile还能防止指令重排序。在创建Singleton实例时new Singleton()操作并非原子操作。它包含三个步骤分配内存空间、初始化对象、将对象引用赋值给instance。如果没有volatile可能会发生指令重排序导致其他线程获取到一个尚未完全初始化的instance对象。private Singleton()私有构造函数确保无法从外部直接实例化Singleton类保证了单例模式的唯一性。public static Singleton getInstance()首先检查instance是否为null。如果不为null直接返回实例避免进入同步代码块提高了性能。如果instance为null进入同步代码块。synchronized (Singleton.class)语句锁定Singleton类确保同一时间只有一个线程能进入创建实例的代码块。再次检查instance是否为null。这是为了防止多个线程同时通过第一次检查进入同步代码块并重复创建实例。当instance为null时执行instance new Singleton();创建单例实例。代码实现 2枚举单例模式这是 Effective Java 中更推荐的单例模式实现方式。public enum SingletonEnum { INSTANCE; public void doSomething() { System.out.println(This is a singleton instance doing something.); } }代码解释枚举类型是 Java 中一种特殊的类。它保证了实例的唯一性并且天生是线程安全的。INSTANCE是SingletonEnum枚举的唯一实例。你可以通过SingletonEnum.INSTANCE获取该单例。你可以在枚举中添加自定义方法如doSomething()来实现单例需要完成的业务逻辑。枚举单例可以防止反射和序列化破坏单例因为 Java 规范保证了枚举类型的实例化是唯一的且在序列化和反序列化过程中不会创建新实例。JDK 中的应用java.lang.Runtime.getRuntime()java.util.logging.LoggerSpring 中的应用默认情况下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) { casecar: returnnew Car(); casebicycle: returnnew Bicycle(); casetruck: 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(); } }代码解释当你需要制造交通工具时不需要直接调用Car、Bicycle或Truck的构造函数而是调用VehicleFactory.createVehicle()方法并传入你想要制造的交通工具类型。工厂会根据你提供的类型创建并返回相应的交通工具实例。你可以通过调用drive()方法来使用制造出来的交通工具。优点代码解耦交通工具的创建逻辑和使用逻辑分离。用户不需要关心具体的交通工具创建过程只需要告诉工厂想要什么类型的交通工具。易于扩展如果你想添加新的交通工具类型只需创建一个新的具体交通工具类并继承Vehicle然后在VehicleFactory的createVehicle()方法中添加相应的创建逻辑即可。例如如果你想添加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) { casecar: returnnew Car(); casebicycle: returnnew Bicycle(); casetruck: returnnew Truck(); casemotorcycle: 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 中的应用java.util.Calendar.getInstance()javax.xml.parsers.DocumentBuilderFactory.newInstance()Spring 中的应用BeanFactory和ApplicationContext都是工厂模式的体现。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 中的应用StringBuilderStream.BuilderSpring 中的应用BeanDefinitionBuilder用于构建BeanDefinition对象这是 Spring 容器管理 Bean 的核心组件。UriComponentsBuilder用于构建 URI。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); } }代码解释首先通过实现TravelStrategy接口定义了不同的出行策略。然后创建TravelPlanner对象并根据需要选择不同的出行策略。最后调用planTravel()方法执行出行操作并使用calculateCost()和calculateTime()方法计算成本和时间。优点易于扩展如果你想添加新的出行方式只需创建一个新的TravelStrategy实现类无需修改TravelPlanner类的代码。灵活切换你可以轻松地在不同出行策略之间切换以满足不同的出行需求。代码清晰不同出行方式的逻辑被封装在各自的策略类中使得代码更具可读性和可维护性。这个例子可以帮助你更好地理解策略模式在实际场景中的应用。通过不同的策略实现不同的行为并能根据用户需求灵活选择和切换策略同时保持了代码的可扩展性和可维护性。此外策略模式通常与工厂模式结合使用可以将策略对象的创建和使用分离使代码更加灵活和易于维护。JDK 中的应用java.util.Comparator是一个典型的策略模式。Spring 中的应用事务管理 (TransactionManager)支持编程式和声明式事务。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 ListStockObserver 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代码解释首先创建一个Stock对象作为主题。创建多个Investor对象作为观察者。使用registerObserver方法将这些投资者注册到Stock对象。当调用setPrice方法更新股价时所有注册的投资者会自动收到通知。你可以使用removeObserver方法移除不需要接收通知的投资者。JDK 中的应用java.util.Observer和java.util.Observablejavax.swing.event.ChangeListenerSpring 中的应用ApplicationEvent和ApplicationListener是典型的实现。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(); } }代码解释Service接口定义了服务的抽象方法execute。RealService类它是实现Service接口的具体类提供了服务的具体实现。ServiceProxy类它是RealService的代理类也实现了Service接口。在execute方法中除了调用真实服务的execute方法外还添加了前后额外的操作实现了代理功能。在StaticProxyExample的main方法中创建一个ServiceProxy对象并调用execute方法实现了对RealService的代理调用。代码实现动态代理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(); } }代码解释DynamicService接口定义了服务的抽象方法performTask。RealDynamicService类它是实现DynamicService接口的具体类提供了服务的具体实现。DynamicServiceInvocationHandler类实现了InvocationHandler接口当代理对象的方法被调用时其invoke方法会被触发。在invoke方法中在调用真实服务方法前后添加了额外操作。在DynamicProxyExample的main方法中首先创建RealDynamicService的实例然后创建DynamicServiceInvocationHandler实例并传入真实服务对象。接着使用Proxy.newProxyInstance方法创建DynamicService的代理对象并调用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...); } }代码解释UserService是一个普通的服务类包含addUser方法。UserServiceAspect是一个切面类使用Before注解定义了一个前置通知。当UserService的addUser方法被调用时Spring 会为UserService创建一个代理对象并在调用addUser方法之前执行beforeAddUser方法。Spring 使用动态代理机制如果是接口则使用 JDK 动态代理否则使用 CGLIB 动态代理在不修改UserService类代码的情况下将切面逻辑织入到UserService的方法调用中从而实现了横切关注点的分离。总结静态代理在编译时确定代理类和被代理类的关系代码简单易懂但如果接口方法较多为每个方法添加代理逻辑会很繁琐。动态代理通过反射机制在运行时生成代理对象更加灵活可以动态添加代理逻辑。适用于需要为多个不同的类或方法添加相同或相似代理逻辑的场景如日志记录、性能统计、权限检查等。Spring AOP 是动态代理在实际框架中的应用它帮助开发者更好地实现面向切面编程将横切关注点如日志、事务、安全等与业务逻辑分离提高了代码的可维护性和可扩展性。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(); } }代码解释BeverageMaker是一个抽象类其中makeBeverage是一个模板方法。它定义了制作饮料的算法骨架即先准备原料然后冲泡接着将饮料倒入杯中最后添加调料。该方法是final的不允许子类修改这个流程的顺序。prepareIngredients、brew和addCondiments是抽象方法。因为不同的饮料准备原料、冲泡和添加调料的方式不同所以这些方法由具体的子类来实现。pourInCup方法是一个有默认实现的方法。对于大多数饮料来说将饮料倒入杯中的操作是相似的但如果子类有特殊需求也可以重写该方法。CoffeeMaker和TeaMaker是BeverageMaker的具体子类。它们分别重写了prepareIngredients、brew和addCondiments方法实现了制作咖啡和茶的具体步骤。在TemplateMethodPatternDemo的main方法中我们创建了CoffeeMaker和TeaMaker的实例并调用它们的makeBeverage方法。这样我们可以看到在不改变整体制作流程的情况下不同的饮料可以按照自己的特点完成各个步骤。这个例子更贴近实际生活。它通过制作饮料的过程展示了模板方法模式如何分离算法的框架和具体实现提高了代码的复用性和可维护性。对于不同的饮料我们只需要关注它们各自的特点而不需要重复实现整个制作流程体现了模板方法模式的优势。通过使用模板方法模式我们可以在保证流程一致性的同时根据具体情况灵活定制不同的步骤使得代码更加清晰、易于扩展和维护。JDK 中的应用java.util.AbstractList和java.util.AbstractMapSpring 中的应用JdbcTemplate和RestTemplate