当前位置: 首页 > news >正文

面向对象设计模式详解

面向对象设计模式详解:从汽车工厂看设计模式的实际应用

引言

设计模式是面向对象软件开发中的"最佳实践",如同汽车制造中的标准化生产流程,它们提供了经过验证的解决方案来应对常见的设计挑战。正如"java进阶.md"中所述,设计模式的概念最初源于建筑领域,1995年由"四人组"(Gang of Four, GoF)引入软件领域,收录了23个经典模式。

在这里插入图片描述

学习设计模式就像学习汽车制造的标准化流程——掌握它们可以帮助开发者构建更可靠、更灵活、更易于维护的软件系统。本文将以汽车制造为核心案例,详细解释9种常用设计模式,让复杂概念变得直观易懂。

设计模式分类

设计模式主要分为三大类,如同汽车制造中的不同环节:

  1. 创建型模式:处理对象创建机制,如同汽车工厂中的生产线设计
  2. 结构型模式:关注类和对象的组合,如同汽车零部件的组装方式
  3. 行为型模式:关注对象之间的通信,如同汽车各系统间的协作机制

一、创建型设计模式

1.1 单例模式(Singleton Pattern)

单例模式确保一个类只有一个实例,并提供一个全局访问点,如同汽车工厂中的中央控制系统——整个工厂只需要一个总控中心。

生活中的单例:汽车工厂的总控中心

在汽车制造中,整个工厂的生产调度系统只能有一个实例,否则会出现调度混乱。单例模式确保无论多少生产线请求调度,都只会与同一个总控中心交互。

实现方式

1. 饿汉式(立即初始化)

// 汽车工厂总控中心(饿汉式单例)
public class ProductionControlCenter {// 类加载时立即初始化实例private static final ProductionControlCenter INSTANCE = new ProductionControlCenter();// 私有构造器,防止外部实例化private ProductionControlCenter() {System.out.println("初始化生产总控中心");}// 全局访问点public static ProductionControlCenter getInstance() {return INSTANCE;}// 调度生产public void scheduleProduction(String carModel) {System.out.println("调度生产: " + carModel);}
}

2. 懒汉式(延迟初始化)

// 汽车工厂总控中心(懒汉式单例)
public class LazyProductionControlCenter {private static LazyProductionControlCenter instance;private LazyProductionControlCenter() {System.out.println("延迟初始化生产总控中心");}// 同步方法确保线程安全public static synchronized LazyProductionControlCenter getInstance() {if (instance == null) {instance = new LazyProductionControlCenter();}return instance;}
}

3. 双重检查锁定(高效线程安全)

public class DoubleCheckedLockingControlCenter {// volatile确保多线程下的可见性private static volatile DoubleCheckedLockingControlCenter instance;private DoubleCheckedLockingControlCenter() {}public static DoubleCheckedLockingControlCenter getInstance() {if (instance == null) { // 第一次检查:避免不必要的同步synchronized (DoubleCheckedLockingControlCenter.class) {if (instance == null) { // 第二次检查:确保只初始化一次instance = new DoubleCheckedLockingControlCenter();}}}return instance;}
}

4. 静态内部类(推荐方式)

public class StaticInnerClassControlCenter {private StaticInnerClassControlCenter() {}// 静态内部类,只有在调用getInstance时才会加载private static class SingletonHolder {private static final StaticInnerClassControlCenter INSTANCE = new StaticInnerClassControlCenter();}public static StaticInnerClassControlCenter getInstance() {return SingletonHolder.INSTANCE;}
}

5. 枚举(最简洁安全的方式)

public enum EnumControlCenter {INSTANCE;public void scheduleProduction(String carModel) {System.out.println("调度生产: " + carModel);}
}
线程安全性对比
实现方式是否线程安全懒加载优点缺点
饿汉式实现简单,绝对安全可能浪费资源
懒汉式(同步方法)实现简单,按需加载性能较差
双重检查锁定性能好,按需加载实现复杂
静态内部类实现简洁,性能好无法传参
枚举绝对安全,防反射无法懒加载
应用场景
  • 配置管理:应用的配置类,确保配置只加载一次
  • 资源池:数据库连接池、线程池,控制资源数量
  • 日志系统:全局日志对象,确保日志输出顺序
  • 设备驱动:如打印机驱动,避免多个驱动实例冲突

1.2 工厂方法模式(Factory Method Pattern)

工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,如同汽车制造中,每个品牌有自己的工厂,生产自己品牌的汽车。

汽车工厂案例:不同品牌的汽车生产线

假设我们要创建一个汽车制造系统,支持不同品牌的汽车生产。使用工厂方法模式,我们可以为每个品牌创建一个具体工厂,负责生产该品牌的汽车。

UML类图
┌───────────────────┐     ┌───────────────────┐
│     Car           │     │   CarFactory      │
├───────────────────┤     ├───────────────────┤
│ +drive()          │     │ +createCar()      │
└───────────────────┘     └───────────────────┘▲                             ▲│                             │
┌───────────────────┐     ┌───────────────────┐
│   BMWCar          │     │   BMWFactory      │
├───────────────────┤     ├───────────────────┤
│ +drive()          │     │ +createCar()      │
└───────────────────┘     └───────────────────┘▲                             ▲│                             │
┌───────────────────┐     ┌───────────────────┐
│  BenzCar          │     │  BenzFactory      │
├───────────────────┤     ├───────────────────┤
│ +drive()          │     │ +createCar()      │
└───────────────────┘     └───────────────────┘
代码示例:汽车品牌工厂

1. 产品接口(汽车)

// 汽车接口
public interface Car {void drive();  // 汽车可以行驶String getBrand();  // 获取品牌
}

2. 具体产品(各品牌汽车)

// 宝马汽车
public class BMWCar implements Car {@Overridepublic void drive() {System.out.println("驾驶宝马汽车,体验纯粹驾驶乐趣");}@Overridepublic String getBrand() {return "BMW";}
}// 奔驰汽车
public class BenzCar implements Car {@Overridepublic void drive() {System.out.println("驾驶奔驰汽车,感受豪华舒适");}@Overridepublic String getBrand() {return "Benz";}
}

3. 抽象工厂(汽车工厂)

// 汽车工厂接口
public abstract class CarFactory {// 工厂方法:创建汽车public abstract Car createCar();// 生产汽车的通用流程public Car produceCar() {Car car = createCar();System.out.println("生产" + car.getBrand() + "汽车");return car;}
}

4. 具体工厂(各品牌工厂)

// 宝马工厂
public class BMWFactory extends CarFactory {@Overridepublic Car createCar() {// 宝马汽车的具体生产过程return new BMWCar();}
}// 奔驰工厂
public class BenzFactory extends CarFactory {@Overridepublic Car createCar() {// 奔驰汽车的具体生产过程return new BenzCar();}
}

5. 客户端代码

public class CarManufacturer {public static void main(String[] args) {// 创建宝马工厂并生产宝马汽车CarFactory bmwFactory = new BMWFactory();Car bmw = bmwFactory.produceCar();bmw.drive();// 创建奔驰工厂并生产奔驰汽车CarFactory benzFactory = new BenzFactory();Car benz = benzFactory.produceCar();benz.drive();// 如果要增加奥迪品牌,只需添加AudiCar和AudiFactory// 无需修改现有代码,符合开闭原则}
}
优点
  • 符合开闭原则:新增产品只需添加新的工厂类,无需修改现有代码
  • 单一职责:每个工厂只负责生产一种类型的产品
  • 解耦:客户端无需知道具体产品的创建细节,只需关心工厂接口
应用场景
  • 框架设计:如Spring中的BeanFactory,允许子类决定实例化哪个Bean
  • 日志系统:不同日志实现(文件日志、数据库日志)对应不同工厂
  • UI组件库:不同平台的UI组件(Windows、Mac)由不同工厂创建

1.3 抽象工厂模式(Abstract Factory Pattern)

抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,如同汽车制造中,每个品牌不仅生产轿车,还生产SUV、跑车等不同系列,形成完整的产品族。

汽车工厂案例:品牌产品族

假设宝马和奔驰不仅生产轿车,还生产SUV。抽象工厂模式可以创建一个抽象工厂,定义生产不同类型汽车的接口,每个品牌工厂实现这个接口,生产完整的产品系列。

UML类图
┌─────────────────────────────────┐
│         AbstractCarFactory      │
├─────────────────────────────────┤
│ +createSedan(): Sedan           │  ← 产品族1:轿车系列
│ +createSUV(): SUV               │  ← 产品族2:SUV系列
└─────────────────────────────────┘▲│┌───────┴───────┐
┌─────────────┐   ┌─────────────┐
│ BMWFactory  │   │ BenzFactory │
├─────────────┤   ├─────────────┤
│ +createSedan()   │ +createSedan()
│ +createSUV()     │ +createSUV()
└─────────────┘   └─────────────┘│                 │▼                 ▼
┌─────────────────────────────────┐
│           具体产品族            │
├─────────────┬──────────────────┤
│  BMW系列    │  Benz系列         │
├─────────────┼──────────────────┤
│ BMWSedan    │ BenzSedan        │
│ BMWSuv      │ BenzSuv          │
└─────────────┴──────────────────┘
代码示例:汽车品牌产品族

1. 产品接口(不同类型汽车)

// 轿车接口
public interface Sedan {void drive();String getBrand();
}// SUV接口
public interface SUV {void drive();String getBrand();void offroad();  // SUV特有方法:越野
}

2. 具体产品(各品牌的不同车型)

// 宝马轿车
public class BMWSedan implements Sedan {@Overridepublic void drive() {System.out.println("驾驶宝马轿车,体验运动操控");}@Overridepublic String getBrand() {return "BMW";}
}// 宝马SUV
public class BMWSuv implements SUV {@Overridepublic void drive() {System.out.println("驾驶宝马SUV,兼顾舒适与通过性");}@Overridepublic String getBrand() {return "BMW";}@Overridepublic void offroad() {System.out.println("宝马SUV越野模式启动");}
}// 奔驰轿车
public class BenzSedan implements Sedan {@Overridepublic void drive() {System.out.println("驾驶奔驰轿车,享受豪华舒适");}@Overridepublic String getBrand() {return "Benz";}
}// 奔驰SUV
public class BenzSuv implements SUV {@Overridepublic void drive() {System.out.println("驾驶奔驰SUV,体验顶级越野性能");}@Overridepublic String getBrand() {return "Benz";}@Overridepublic void offroad() {System.out.println("奔驰SUV全地形模式启动");}
}

3. 抽象工厂(汽车品牌工厂)

// 汽车品牌工厂接口,定义完整产品族
public interface AbstractCarFactory {Sedan createSedan();  // 生产轿车SUV createSUV();      // 生产SUV
}

4. 具体工厂(各品牌工厂)

// 宝马工厂,生产宝马全系列车型
public class BMWFactory implements AbstractCarFactory {@Overridepublic Sedan createSedan() {return new BMWSedan();}@Overridepublic SUV createSUV() {return new BMWSuv();}
}// 奔驰工厂,生产奔驰全系列车型
public class BenzFactory implements AbstractCarFactory {@Overridepublic Sedan createSedan() {return new BenzSedan();}@Overridepublic SUV createSUV() {return new BenzSuv();}
}

5. 客户端代码

public class LuxuryCarManufacturer {public static void main(String[] args) {// 创建宝马工厂,生产宝马全系列AbstractCarFactory bmwFactory = new BMWFactory();Sedan bmwSedan = bmwFactory.createSedan();SUV bmwSuv = bmwFactory.createSUV();bmwSedan.drive();  // 驾驶宝马轿车bmwSuv.offroad();  // 宝马SUV越野// 创建奔驰工厂,生产奔驰全系列AbstractCarFactory benzFactory = new BenzFactory();Sedan benzSedan = benzFactory.createSedan();SUV benzSuv = benzFactory.createSUV();benzSedan.drive();  // 驾驶奔驰轿车benzSuv.offroad();  // 奔驰SUV越野}
}
抽象工厂 vs 工厂方法
特性工厂方法模式抽象工厂模式
产品数量单一产品等级结构多个产品等级结构(产品族)
核心思想定义创建单个产品的接口定义创建一系列相关产品的接口
灵活性易于扩展单个产品易于替换整个产品族
复杂度较低较高
典型案例不同品牌的单一车型同一品牌的全系列车型
优点
  • 产品族一致性:确保同一品牌的不同产品(如宝马轿车和SUV)能够协同工作
  • 易于切换产品族:只需更换工厂即可切换整套产品(如从宝马产品线切换到奔驰产品线)
  • 隔离具体实现:客户端只与抽象接口交互,不依赖具体产品实现
缺点
  • 扩展困难:新增产品类型(如添加跑车系列)需要修改抽象工厂接口和所有具体工厂
  • 复杂度高:需要理解多个产品等级结构和产品族的概念
应用场景
  • 跨平台应用:为不同平台(Windows、Mac、Linux)提供整套UI组件
  • 主题系统:为应用提供不同主题(浅色、深色)的全套界面元素
  • 数据库访问:为不同数据库(MySQL、Oracle)提供整套访问接口

二、结构型设计模式

2.1 适配器模式(Adapter Pattern)

适配器模式将一个类的接口转换成客户希望的另一个接口,如同不同国家的电源插座需要适配器才能通用,汽车领域中不同品牌的零件接口也需要适配器来兼容。

汽车案例:充电接口适配器

随着电动汽车的发展,不同品牌可能采用不同的充电接口标准。为了让特斯拉充电桩能给宝马电动车充电,我们需要一个充电接口适配器。

类适配器UML
┌───────────────────┐            ┌───────────────────┐
│   Target (宝马接口) │            │ Adaptee (特斯拉接口)│
├───────────────────┤            ├───────────────────┤
│ +chargeWithBMW()  │            │ +chargeWithTesla()│
└───────────────────┘            └───────────────────┘△                              ▲│ 实现                         │ 继承
┌───────────────────────────────────────┘
│           Adapter (充电适配器)
├───────────────────┤
│ +chargeWithBMW()  │
└───────────────────┘
代码示例:充电接口适配器

1. 目标接口(宝马充电接口)

// 宝马充电接口标准
public interface BMWChargeInterface {void chargeWithBMW();
}

2. 被适配者(特斯拉充电接口)

// 特斯拉充电接口标准
public class TeslaChargeInterface {// 特斯拉特有充电方法public void chargeWithTesla() {System.out.println("使用特斯拉充电接口充电");}
}

3. 类适配器(充电适配器)

// 充电适配器:将特斯拉接口适配为宝马接口
public class ChargeAdapter extends TeslaChargeInterface implements BMWChargeInterface {@Overridepublic void chargeWithBMW() {// 适配过程:调用特斯拉的充电方法System.out.println("使用适配器转换接口...");super.chargeWithTesla();System.out.println("适配器转换完成,宝马汽车充电中...");}
}

4. 对象适配器(更灵活的方式)

// 对象适配器:通过组合方式实现适配
public class ChargeObjectAdapter implements BMWChargeInterface {private TeslaChargeInterface teslaInterface;// 注入被适配对象public ChargeObjectAdapter(TeslaChargeInterface teslaInterface) {this.teslaInterface = teslaInterface;}@Overridepublic void chargeWithBMW() {System.out.println("对象适配器:转换接口...");teslaInterface.chargeWithTesla();System.out.println("对象适配器:宝马汽车充电中...");}
}

5. 客户端代码

public class ElectricCar {public static void main(String[] args) {// 类适配器使用BMWChargeInterface classAdapter = new ChargeAdapter();classAdapter.chargeWithBMW();// 对象适配器使用TeslaChargeInterface teslaInterface = new TeslaChargeInterface();BMWChargeInterface objectAdapter = new ChargeObjectAdapter(teslaInterface);objectAdapter.chargeWithBMW();}
}
类适配器 vs 对象适配器
类型实现方式优点缺点
类适配器继承被适配者,实现目标接口结构简单,可重写被适配者方法受单继承限制,耦合度高
对象适配器持有被适配者引用,实现目标接口更灵活,可适配多个被适配者结构稍复杂,需要额外对象
应用场景
  • 系统集成:整合不同厂商的API接口
  • 版本兼容:为旧系统提供新接口适配
  • 第三方库使用:适配第三方库以符合项目接口标准

2.2 装饰器模式(Decorator Pattern)

装饰器模式动态地给对象添加一些额外的职责,如同汽车在基础配置上选装不同配件(导航、真皮座椅、全景天窗等),每个选装件都是一个装饰器。

汽车案例:汽车配置选装系统

假设我们要设计一个汽车配置系统,客户可以在基础车型上添加各种选装配置。使用装饰器模式,每个选装件都是一个装饰器,可以动态组合。

代码示例:汽车配置选装

1. 抽象组件(汽车)

// 汽车接口
public interface Car {String getDescription();  // 获取配置描述double getPrice();        // 获取价格
}

2. 具体组件(基础车型)

// 基础款宝马
public class BasicBMW implements Car {@Overridepublic String getDescription() {return "宝马3系基础款";}@Overridepublic double getPrice() {return 350000;  // 基础价格35万}
}// 基础款奔驰
public class BasicBenz implements Car {@Overridepublic String getDescription() {return "奔驰C级基础款";}@Overridepublic double getPrice() {return 380000;  // 基础价格38万}
}

3. 抽象装饰器(选装配置)

// 汽车配置装饰器
public abstract class CarDecorator implements Car {protected Car decoratedCar;  // 被装饰的汽车public CarDecorator(Car car) {this.decoratedCar = car;}@Overridepublic String getDescription() {return decoratedCar.getDescription();}@Overridepublic double getPrice() {return decoratedCar.getPrice();}
}

4. 具体装饰器(各种选装件)

// 导航系统
public class NavigationSystem extends CarDecorator {public NavigationSystem(Car car) {super(car);}@Overridepublic String getDescription() {return super.getDescription() + " + 高级导航系统";}@Overridepublic double getPrice() {return super.getPrice() + 8000;  // 导航系统加价8000}
}// 真皮座椅
public class LeatherSeats extends CarDecorator {public LeatherSeats(Car car) {super(car);}@Overridepublic String getDescription() {return super.getDescription() + " + 真皮座椅";}@Overridepublic double getPrice() {return super.getPrice() + 15000;  // 真皮座椅加价15000}
}// 全景天窗
public class PanoramicSunroof extends CarDecorator {public PanoramicSunroof(Car car) {super(car);}@Overridepublic String getDescription() {return super.getDescription() + " + 全景天窗";}@Overridepublic double getPrice() {return super.getPrice() + 12000;  // 全景天窗加价12000}
}

5. 客户端代码

public class CarConfiguration {public static void main(String[] args) {// 创建基础款宝马Car bmw = new BasicBMW();System.out.println(bmw.getDescription() + ",价格:" + bmw.getPrice());// 添加导航系统bmw = new NavigationSystem(bmw);System.out.println(bmw.getDescription() + ",价格:" + bmw.getPrice());// 添加真皮座椅bmw = new LeatherSeats(bmw);System.out.println(bmw.getDescription() + ",价格:" + bmw.getPrice());// 添加全景天窗bmw = new PanoramicSunroof(bmw);System.out.println(bmw.getDescription() + ",价格:" + bmw.getPrice());// 创建一个高配奔驰Car benz = new PanoramicSunroof(new LeatherSeats(new NavigationSystem(new BasicBenz())));System.out.println(benz.getDescription() + ",价格:" + benz.getPrice());}
}
优点
  • 动态扩展:可以在运行时动态添加或移除功能
  • 组合灵活:不同装饰器可以任意组合,实现多种配置
  • 遵循开闭原则:新增装饰器无需修改现有代码
  • 避免类爆炸:无需为每种组合创建单独的类
应用场景
  • IO流:Java中的InputStream、OutputStream使用装饰器模式
  • GUI组件:如Swing中的JScrollPane装饰JTextArea
  • 权限控制:动态添加不同级别的权限检查
  • 日志记录:动态添加日志记录功能

2.3 代理模式(Proxy Pattern)

代理模式为其他对象提供一种代理以控制对这个对象的访问,如同汽车销售代理商,客户通过代理商购买汽车,而不是直接与汽车工厂打交道。

汽车案例:汽车销售代理

汽车制造商通常不直接向消费者销售汽车,而是通过4S店代理商。代理商可以提供额外服务(如贷款、保险、上牌等),同时控制对制造商的访问。

代码示例:汽车销售代理

1. 抽象主题(汽车销售)

// 汽车销售接口
public interface CarSales {void sellCar(String model);  // 销售汽车void serviceCar(String model);  // 汽车维修
}

2. 真实主题(汽车制造商)

// 汽车制造商
public class CarManufacturer implements CarSales {private String name;public CarManufacturer(String name) {this.name = name;}@Overridepublic void sellCar(String model) {System.out.println(name + "工厂生产并销售" + model + "汽车");}@Overridepublic void serviceCar(String model) {System.out.println(name + "工厂提供" + model + "汽车维修服务");}
}

3. 代理(4S店代理商)

// 汽车4S店代理
public class CarDealerProxy implements CarSales {private CarManufacturer manufacturer;  // 被代理的制造商private String dealerName;  // 代理商名称public CarDealerProxy(String manufacturerName, String dealerName) {this.manufacturer = new CarManufacturer(manufacturerName);this.dealerName = dealerName;}@Overridepublic void sellCar(String model) {// 代理前:提供额外服务System.out.println(dealerName + "提供贷款咨询服务");System.out.println(dealerName + "提供保险服务");// 调用真实主题的方法manufacturer.sellCar(model);// 代理后:提供售后服务System.out.println(dealerName + "提供上牌服务");System.out.println(dealerName + "提供免费保养券");}@Overridepublic void serviceCar(String model) {// 控制对真实主题的访问System.out.println(dealerName + "检查车辆故障");// 只有复杂问题才交给工厂处理if (isComplexIssue(model)) {manufacturer.serviceCar(model);} else {System.out.println(dealerName + "直接提供维修服务");}}// 判断是否是复杂问题private boolean isComplexIssue(String model) {// 简化逻辑:假设某些车型问题较复杂return model.contains("新能源");}
}

4. 客户端代码

public class Customer {public static void main(String[] args) {// 客户通过4S店代理购买汽车CarSales bmwDealer = new CarDealerProxy("宝马", "宝诚宝马4S店");bmwDealer.sellCar("宝马3系");System.out.println("\n--- 汽车维修 ---");bmwDealer.serviceCar("宝马3系");  // 普通车型,4S店直接维修bmwDealer.serviceCar("宝马iX3新能源");  // 新能源车型,需要工厂支持}
}
代理模式的类型
类型用途示例
远程代理代表远程对象分布式系统中的远程服务调用
虚拟代理延迟初始化重量级对象图片懒加载
保护代理控制访问权限权限验证
智能引用提供额外服务引用计数、缓存
优点
  • 职责分离:真实主题只需关注核心功能,代理处理辅助功能
  • 控制访问:可以限制或管理对真实主题的访问
  • 增强功能:可以在不修改真实主题的情况下添加额外功能
  • 远程代理:可以隐藏对象位于远程地址空间的事实

三、行为型设计模式

3.1 观察者模式(Observer Pattern)

观察者模式定义了对象之间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都会收到通知并自动更新,如同汽车的仪表盘,发动机转速、车速等数据变化时,仪表盘上的指针会自动更新。

汽车案例:汽车仪表盘系统

汽车的仪表盘需要实时显示发动机转速、车速、油量等信息。当这些数据变化时,仪表盘上的相应指示器应立即更新。观察者模式非常适合这种场景。

代码示例:汽车仪表盘

1. 主题接口(被观察者)

import java.util.ArrayList;
import java.util.List;// 汽车数据主题
public interface CarDataSubject {void registerObserver(Observer observer);  // 注册观察者void removeObserver(Observer observer);    // 移除观察者void notifyObservers();                    // 通知所有观察者
}

2. 观察者接口

// 观察者接口
public interface Observer {void update(float speed, float rpm, float fuelLevel);  // 更新数据
}

3. 具体主题(汽车传感器系统)

// 汽车传感器系统
public class CarSensorSystem implements CarDataSubject {private List<Observer> observers;private float speed;      // 车速(km/h)private float rpm;        // 发动机转速(rpm)private float fuelLevel;  // 油量(0-100%)public CarSensorSystem() {observers = new ArrayList<>();}@Overridepublic void registerObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers() {for (Observer observer : observers) {observer.update(speed, rpm, fuelLevel);}}// 当传感器数据变化时调用public void sensorDataChanged() {notifyObservers();}// 设置传感器数据public void setSensorData(float speed, float rpm, float fuelLevel) {this.speed = speed;this.rpm = rpm;this.fuelLevel = fuelLevel;sensorDataChanged();  // 数据变化,通知观察者}
}

4. 具体观察者(仪表盘)

// 车速表
public class SpeedMeter implements Observer {private String name;public SpeedMeter(String name) {this.name = name;}@Overridepublic void update(float speed, float rpm, float fuelLevel) {System.out.println(name + "显示车速: " + speed + " km/h");}
}// 转速表
public class RpmMeter implements Observer {private String name;public RpmMeter(String name) {this.name = name;}@Overridepublic void update(float speed, float rpm, float fuelLevel) {System.out.println(name + "显示转速: " + rpm + " rpm");}
}// 油量表
public class FuelGauge implements Observer {private String name;public FuelGauge(String name) {this.name = name;}@Overridepublic void update(float speed, float rpm, float fuelLevel) {System.out.println(name + "显示油量: " + fuelLevel + "%");if (fuelLevel < 10) {System.out.println("警告: 油量过低,请尽快加油!");}}
}

5. 客户端代码

public class CarDashboard {public static void main(String[] args) {// 创建汽车传感器系统CarSensorSystem sensorSystem = new CarSensorSystem();// 创建仪表盘组件Observer speedMeter = new SpeedMeter("车速表");Observer rpmMeter = new RpmMeter("转速表");Observer fuelGauge = new FuelGauge("油量表");// 注册观察者sensorSystem.registerObserver(speedMeter);sensorSystem.registerObserver(rpmMeter);sensorSystem.registerObserver(fuelGauge);// 模拟驾驶过程中的数据变化System.out.println("--- 启动汽车 ---");sensorSystem.setSensorData(0, 800, 80);System.out.println("\n--- 加速 ---");sensorSystem.setSensorData(60, 2500, 78);System.out.println("\n--- 高速行驶 ---");sensorSystem.setSensorData(120, 3500, 70);System.out.println("\n--- 油量不足 ---");sensorSystem.setSensorData(80, 2000, 8);}
}
优点
  • 松耦合:主题和观察者之间通过接口通信,互不依赖具体实现
  • 动态关联:可以随时添加或移除观察者,灵活性高
  • 广播通信:主题可以同时通知多个观察者,实现一对多通信
应用场景
  • 事件处理系统:如GUI中的按钮点击事件
  • 消息通知系统:如邮件订阅、消息推送
  • 监控系统:如服务器监控、设备状态监控
  • 数据绑定:如MVVM模式中的视图与数据模型绑定

3.2 策略模式(Strategy Pattern)

策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,如同汽车的驾驶模式选择(经济模式、运动模式、雪地模式等),每种模式对应不同的驾驶策略。

汽车案例:驾驶模式选择系统

现代汽车通常提供多种驾驶模式选择,不同模式下发动机、变速箱等工作方式不同。使用策略模式,可以将每种驾驶模式封装为一个策略,动态切换。

代码示例:驾驶模式策略

1. 策略接口(驾驶模式)

// 驾驶模式策略接口
public interface DrivingMode {void accelerate();    // 加速特性void decelerate();    // 减速特性void steer();         // 转向特性String getModeName(); // 获取模式名称
}

2. 具体策略(各种驾驶模式)

// 经济模式
public class EconomyMode implements DrivingMode {@Overridepublic void accelerate() {System.out.println("经济模式:平缓加速,节省燃油");}@Overridepublic void decelerate() {System.out.println("经济模式:提前减速,能量回收");}@Overridepublic void steer() {System.out.println("经济模式:转向轻盈,适合城市驾驶");}@Overridepublic String getModeName() {return "经济模式";}
}// 运动模式
public class SportMode implements DrivingMode {@Overridepublic void accelerate() {System.out.println("运动模式:快速加速,动力强劲");}@Overridepublic void decelerate() {System.out.println("运动模式:延迟减速,保持动力");}@Overridepublic void steer() {System.out.println("运动模式:转向沉稳,路感清晰");}@Overridepublic String getModeName() {return "运动模式";}
}// 雪地模式
public class SnowMode implements DrivingMode {@Overridepublic void accelerate() {System.out.println("雪地模式:缓慢加速,防止打滑");}@Overridepublic void decelerate() {System.out.println("雪地模式:轻柔减速,避免抱死");}@Overridepublic void steer() {System.out.println("雪地模式:转向柔和,减少侧滑");}@Overridepublic String getModeName() {return "雪地模式";}
}

3. 上下文(汽车控制系统)

// 汽车控制系统
public class CarControlSystem {private DrivingMode currentMode;// 默认使用经济模式public CarControlSystem() {this.currentMode = new EconomyMode();}// 设置驾驶模式public void setDrivingMode(DrivingMode mode) {this.currentMode = mode;System.out.println("\n切换到" + mode.getModeName());}// 执行加速public void accelerate() {currentMode.accelerate();}// 执行减速public void decelerate() {currentMode.decelerate();}// 执行转向public void steer() {currentMode.steer();}
}

4. 客户端代码

public class Driver {public static void main(String[] args) {CarControlSystem car = new CarControlSystem();// 默认经济模式驾驶System.out.println("--- 城市通勤 ---");car.accelerate();car.steer();car.decelerate();// 切换到运动模式car.setDrivingMode(new SportMode());System.out.println("--- 高速公路 ---");car.accelerate();car.steer();car.decelerate();// 切换到雪地模式car.setDrivingMode(new SnowMode());System.out.println("--- 雪地行驶 ---");car.accelerate();car.steer();car.decelerate();}
}
优点
  • 策略切换灵活:可以在运行时动态切换算法
  • 避免多重条件判断:用多态代替复杂的if-else或switch语句
  • 单一职责原则:每个策略只负责一种算法
  • 开闭原则:新增策略无需修改现有代码
应用场景
  • 排序算法:不同数据规模使用不同排序算法
  • 支付方式:支付宝、微信支付、银行卡支付等不同策略
  • 压缩算法:不同文件类型使用不同压缩算法
  • 校验规则:不同表单字段使用不同校验规则

3.3 模板方法模式(Template Method Pattern)

模板方法模式定义了一个算法的骨架,将某些步骤延迟到子类中实现,如同汽车生产的总装流程——总流程固定(底盘→发动机→车身→内饰),但各步骤的具体实现因车型而异。

汽车案例:汽车组装流程

汽车制造中的总装流程有固定的步骤顺序,但不同车型的具体组装细节不同。模板方法模式可以定义总流程骨架,具体车型实现细节步骤。

代码示例:汽车组装模板

1. 抽象类(组装模板)

// 汽车组装模板
public abstract class CarAssemblyTemplate {// 模板方法:定义组装流程骨架public final void assembleCar() {assembleChassis();    // 组装底盘installEngine();      // 安装发动机assembleBody();       // 组装车身installInterior();    // 安装内饰qualityCheck();       // 质量检查if (needsSpecialEquipment()) {  // 钩子方法:是否需要特殊设备installSpecialEquipment();  // 安装特殊设备}}// 具体方法:通用底盘组装protected void assembleChassis() {System.out.println("1. 组装通用底盘");}// 抽象方法:不同车型发动机安装不同protected abstract void installEngine();// 抽象方法:不同车型车身组装不同protected abstract void assembleBody();// 具体方法:通用内饰安装protected void installInterior() {System.out.println("4. 安装通用内饰");}// 钩子方法:质量检查,子类可重写protected void qualityCheck() {System.out.println("5. 执行标准质量检查");}// 钩子方法:是否需要特殊设备,默认不需要protected boolean needsSpecialEquipment() {return false;}// 钩子方法:安装特殊设备,默认空实现protected void installSpecialEquipment() {// 子类根据需要实现}
}

2. 具体子类(不同车型组装)

// 轿车组装
public class SedanAssembly extends CarAssemblyTemplate {@Overrideprotected void installEngine() {System.out.println("2. 安装轿车专用发动机");}@Overrideprotected void assembleBody() {System.out.println("3. 组装轿车车身");}
}// SUV组装
public class SUVAssembly extends CarAssemblyTemplate {@Overrideprotected void installEngine() {System.out.println("2. 安装SUV专用大功率发动机");}@Overrideprotected void assembleBody() {System.out.println("3. 组装SUV高底盘车身");}// 重写钩子方法:SUV需要特殊设备@Overrideprotected boolean needsSpecialEquipment() {return true;}// 实现特殊设备安装@Overrideprotected void installSpecialEquipment() {System.out.println("6. 安装四驱系统和越野套件");}
}// 新能源汽车组装
public class ElectricCarAssembly extends CarAssemblyTemplate {@Overrideprotected void installEngine() {System.out.println("2. 安装电动马达和电池组");}@Overrideprotected void assembleBody() {System.out.println("3. 组装轻量化电动车身");}// 重写质量检查方法@Overrideprotected void qualityCheck() {super.qualityCheck();  // 调用父类标准检查System.out.println("5.1 执行电池安全专项检查");System.out.println("5.2 执行电动系统功能检查");}
}

3. 客户端代码

public class CarAssemblyLine {public static void main(String[] args) {System.out.println("=== 组装轿车 ===");CarAssemblyTemplate sedan = new SedanAssembly();sedan.assembleCar();System.out.println("\n=== 组装SUV ===");CarAssemblyTemplate suv = new SUVAssembly();suv.assembleCar();System.out.println("\n=== 组装新能源汽车 ===");CarAssemblyTemplate electricCar = new ElectricCarAssembly();electricCar.assembleCar();}
}
模板方法中的方法类型
方法类型特点作用
抽象方法必须由子类实现定义可变步骤
具体方法父类提供实现定义固定步骤
钩子方法父类提供默认实现,子类可重写定义可选步骤或条件步骤
优点
  • 代码复用:将公共步骤实现放在父类,避免重复
  • 控制流程:父类控制算法骨架,子类专注实现细节
  • 扩展性好:新增具体子类即可扩展新功能
  • 符合开闭原则:算法骨架固定,具体步骤可扩展
应用场景
  • 框架设计:如Spring中的HttpServlet,定义请求处理流程
  • 生命周期管理:如Android中的Activity生命周期
  • 报表生成:固定报表格式,不同数据来源实现细节
  • 测试流程:固定测试流程,不同测试对象实现测试细节

总结

设计模式是面向对象设计的"工具箱",掌握它们可以帮助开发者构建更优秀的软件系统。本文以汽车制造为核心案例,详细解释了9种常用设计模式:

创建型模式

  • 单例模式:确保系统中只有一个实例,如汽车工厂的总控中心
  • 工厂方法模式:每个产品由专门的工厂生产,如不同品牌的汽车工厂
  • 抽象工厂模式:生产完整的产品族,如同一品牌的全系列车型

结构型模式

  • 适配器模式:解决接口不兼容问题,如不同品牌汽车的充电接口适配
  • 装饰器模式:动态添加功能,如汽车选装配置系统
  • 代理模式:控制对象访问,如汽车销售代理商

行为型模式

  • 观察者模式:对象间的一对多通知,如汽车仪表盘系统
  • 策略模式:封装不同算法,如汽车驾驶模式选择
  • 模板方法模式:定义算法骨架,如汽车组装流程

如何选择设计模式

  1. 根据问题类型:创建对象问题用创建型模式,组合对象问题用结构型模式,对象交互问题用行为型模式
  2. 根据设计原则:优先考虑开闭原则、单一职责原则
  3. 避免过度设计:不要为了使用模式而使用模式,简单问题用简单方案
  4. 结合实际场景:理解业务需求,选择最适合的模式

设计模式虽然平时感觉不怎么用到,但它们是解决常见设计问题的经过验证的方案。通过的汽车制造案例,希望您能更直观地理解这些模式的本质和应用场景,在实际开发中灵活运用,构建出更优雅、更灵活、更易于维护的软件系统。

http://www.dtcms.com/a/277449.html

相关文章:

  • CD49.【C++ Dev】容器适配器模式
  • 深入解析5G核心网容灾:UDM 故障场景下 SMF 容灾机制深度解析
  • C++ 单例模式实现
  • 【读书笔记】《C++ Software Design》第五章:The Strategy and Command Design Patterns
  • Java学习------设计模式(1)
  • ZKmall开源商城技术攻略:轻松掌握规则引擎与Spring Boot3接口的开发技巧
  • Linux V4L2应用编程常用结构体介绍
  • STEP 7-Micro/WIN SMART 编程软件:从入门到精通的使用指南
  • 面试150 从前序与中序遍历构造二叉树
  • STM32-第五节-TIM定时器-1(定时器中断)
  • Clojure和Golang中的Channel有什么异同(TBC)
  • 构建应用内智能:衡石嵌入式BI如何打造“指标中台”驱动的场景化分析
  • Python文件路径操作全面指南:从基础到高级应用
  • 深入理解数据库连接池:原理、实现与Druid实战
  • MCU中的系统控制器(System Controller)是什么?
  • Spring Boot + MyBatis 实现用户登录功能详解(基础)
  • PaperPel
  • Oracle SQL - 使用行转列PIVOT减少表重复扫描(实例)
  • AI驱动的软件工程(上):人机协同的设计与建模
  • 【读书笔记】《C++ Software Design》第六章深入剖析 Adapter、Observer 和 CRTP 模式
  • 实现“micro 关键字搜索全覆盖商品”并通过 API 接口提供实时数据(一个方法)
  • fatal: active `post-checkout` hook found during `git clone`
  • mapstruct与lombok冲突原因及解决方案
  • 【Linux 学习指南】网络基础概念(一):从协议到分层,看透计算机通信的底层逻辑
  • LeetCode|Day9|976. 三角形的最大周长|Python刷题笔记
  • 通过反射,提取 Cat 类 泛型 父类 接口 属性 的具体类型参数
  • 【一起来学AI大模型】部署优化推理加速:TensorRT-LLM
  • 华为交换机 undo negotiation auto功能(华为交换机端口接光纤两端起不来)
  • Jvm优化高手-笔记
  • Cursor精准上下文指定