牛刀小试之设计模式
牛刀小试设计模式
目录
- 设计模式简介
- 设计模式分类
- 设计模式使用场景
- 设计模式重难点分析
- 设计模式在实际项目中的应用
- 设计模式最佳实践
- 总结
设计模式简介
什么是设计模式
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它描述了在软件设计过程中一些不断重复出现的问题,以及该问题的解决方案。
设计模式的核心价值
1. 提高代码质量
- 可读性:使用标准化的模式,代码更容易理解
- 可维护性:结构清晰,便于修改和扩展
- 可复用性:模式化的代码更容易在不同项目中复用
2. 解决常见问题
- 解耦:降低类之间的耦合度
- 扩展:便于功能的扩展和修改
- 复用:提高代码的复用性
3. 团队协作
- 沟通:团队成员对设计模式有共同理解
- 规范:统一的代码设计规范
- 效率:减少重复思考和设计时间
设计模式的历史
时间 | 重要事件 | 影响 |
---|---|---|
1977年 | Christopher Alexander提出建筑模式概念 | 为软件设计模式奠定基础 |
1994年 | Gang of Four (GoF) 发布《设计模式》 | 正式确立23种经典设计模式 |
2002年 | Martin Fowler发布《企业应用架构模式》 | 扩展了企业级应用设计模式 |
2008年 | 微服务架构兴起 | 涌现出新的架构模式 |
2014年 | 响应式编程模式 | 适应现代异步编程需求 |
设计模式分类
按目的分类
1. 创建型模式(Creational Patterns)
目的:解决对象创建的问题
模式名称 | 英文名称 | 主要作用 | 使用频率 |
---|---|---|---|
单例模式 | Singleton | 确保一个类只有一个实例 | ⭐⭐⭐⭐⭐ |
工厂方法模式 | Factory Method | 创建对象而不指定具体类 | ⭐⭐⭐⭐ |
抽象工厂模式 | Abstract Factory | 创建相关对象族 | ⭐⭐⭐ |
建造者模式 | Builder | 分步构建复杂对象 | ⭐⭐⭐ |
原型模式 | Prototype | 通过克隆创建对象 | ⭐⭐ |
2. 结构型模式(Structural Patterns)
目的:解决类和对象的组合问题
模式名称 | 英文名称 | 主要作用 | 使用频率 |
---|---|---|---|
适配器模式 | Adapter | 让不兼容的接口协同工作 | ⭐⭐⭐⭐ |
装饰器模式 | Decorator | 动态添加功能 | ⭐⭐⭐⭐ |
代理模式 | Proxy | 为对象提供代理控制访问 | ⭐⭐⭐⭐ |
外观模式 | Facade | 为子系统提供统一接口 | ⭐⭐⭐ |
桥接模式 | Bridge | 分离抽象和实现 | ⭐⭐ |
组合模式 | Composite | 树形结构处理 | ⭐⭐ |
享元模式 | Flyweight | 共享细粒度对象 | ⭐ |
3. 行为型模式(Behavioral Patterns)
目的:解决对象间的通信和职责分配问题
模式名称 | 英文名称 | 主要作用 | 使用频率 |
---|---|---|---|
观察者模式 | Observer | 定义一对多依赖关系 | ⭐⭐⭐⭐⭐ |
策略模式 | Strategy | 定义算法族,使它们可互换 | ⭐⭐⭐⭐ |
命令模式 | Command | 将请求封装为对象 | ⭐⭐⭐⭐ |
模板方法模式 | Template Method | 定义算法骨架 | ⭐⭐⭐⭐ |
状态模式 | State | 改变对象行为 | ⭐⭐⭐ |
责任链模式 | Chain of Responsibility | 避免请求发送者和接收者耦合 | ⭐⭐⭐ |
迭代器模式 | Iterator | 顺序访问聚合对象 | ⭐⭐⭐ |
中介者模式 | Mediator | 减少对象间直接交互 | ⭐⭐ |
备忘录模式 | Memento | 保存和恢复对象状态 | ⭐⭐ |
访问者模式 | Visitor | 在不改变类结构下定义新操作 | ⭐ |
解释器模式 | Interpreter | 定义语言语法 | ⭐ |
按范围分类
1. 类模式
- 处理类与子类之间的关系
- 通过继承建立关系
- 编译时确定关系
典型模式:
- 模板方法模式
- 工厂方法模式
- 适配器模式(类适配器)
2. 对象模式
- 处理对象间的关系
- 通过组合建立关系
- 运行时确定关系
典型模式:
- 单例模式
- 观察者模式
- 策略模式
- 装饰器模式
设计模式使用场景
创建型模式使用场景
1. 单例模式
适用场景:
- 需要全局唯一实例的类
- 资源管理器(数据库连接池、线程池)
- 配置管理器
- 日志记录器
// 线程安全的单例模式
public class DatabaseConnection {private static volatile DatabaseConnection instance;private DatabaseConnection() {}public static DatabaseConnection getInstance() {if (instance == null) {synchronized (DatabaseConnection.class) {if (instance == null) {instance = new DatabaseConnection();}}}return instance;}
}
2. 工厂方法模式
适用场景:
- 创建对象时不知道具体类型
- 需要根据条件创建不同对象
- 希望扩展产品类型
// 支付方式工厂
public interface PaymentFactory {Payment createPayment();
}public class AlipayFactory implements PaymentFactory {@Overridepublic Payment createPayment() {return new AlipayPayment();}
}public class WechatPayFactory implements PaymentFactory {@Overridepublic Payment createPayment() {return new WechatPayPayment();}
}
3. 建造者模式
适用场景:
- 构建复杂对象
- 需要分步构建
- 构建过程需要灵活配置
// 用户信息建造者
public class User {private String name;private String email;private int age;private String address;private User(Builder builder) {this.name = builder.name;this.email = builder.email;this.age = builder.age;this.address = builder.address;}public static class Builder {private String name;private String email;private int age;private String address;public Builder name(String name) {this.name = name;return this;}public Builder email(String email) {this.email = email;return this;}public Builder age(int age) {this.age = age;return this;}public Builder address(String address) {this.address = address;return this;}public User build() {return new User(this);}}
}
结构型模式使用场景
1. 适配器模式
适用场景:
- 使用第三方库时接口不匹配
- 系统升级时保持向后兼容
- 集成不同厂商的组件
// 媒体播放器适配器
public interface MediaPlayer {void play(String audioType, String fileName);
}public interface AdvancedMediaPlayer {void playVlc(String fileName);void playMp4(String fileName);
}public class MediaAdapter implements MediaPlayer {AdvancedMediaPlayer advancedMusicPlayer;public MediaAdapter(String audioType) {if (audioType.equalsIgnoreCase("vlc")) {advancedMusicPlayer = new VlcPlayer();} else if (audioType.equalsIgnoreCase("mp4")) {advancedMusicPlayer = new Mp4Player();}}@Overridepublic void play(String audioType, String fileName) {if (audioType.equalsIgnoreCase("vlc")) {advancedMusicPlayer.playVlc(fileName);} else if (audioType.equalsIgnoreCase("mp4")) {advancedMusicPlayer.playMp4(fileName);}}
}
2. 装饰器模式
适用场景:
- 需要动态添加功能
- 不能使用继承时
- 需要透明地扩展对象功能
// 咖啡装饰器
public abstract class Coffee {public abstract String getDescription();public abstract double cost();
}public class SimpleCoffee extends Coffee {@Overridepublic String getDescription() {return "Simple coffee";}@Overridepublic double cost() {return 1.0;}
}public abstract class CoffeeDecorator extends Coffee {protected Coffee coffee;public CoffeeDecorator(Coffee coffee) {this.coffee = coffee;}
}public class MilkDecorator extends CoffeeDecorator {public MilkDecorator(Coffee coffee) {super(coffee);}@Overridepublic String getDescription() {return coffee.getDescription() + ", milk";}@Overridepublic double cost() {return coffee.cost() + 0.5;}
}
3. 代理模式
适用场景:
- 需要控制对对象的访问
- 延迟加载
- 缓存代理
- 权限控制
// 图片代理
public interface Image {void display();
}public class RealImage implements Image {private String fileName;public RealImage(String fileName) {this.fileName = fileName;loadFromDisk(fileName);}@Overridepublic void display() {System.out.println("Displaying " + fileName);}private void loadFromDisk(String fileName) {System.out.println("Loading " + fileName);}
}public class ProxyImage implements Image {private RealImage realImage;private String fileName;public ProxyImage(String fileName) {this.fileName = fileName;}@Overridepublic void display() {if (realImage == null) {realImage = new RealImage(fileName);}realImage.display();}
}
行为型模式使用场景
1. 观察者模式
适用场景:
- 一对多依赖关系
- 事件处理系统
- 模型-视图架构
- 发布-订阅系统
// 新闻发布订阅系统
public interface Observer {void update(String news);
}public interface Subject {void registerObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers();
}public class NewsAgency implements Subject {private List<Observer> observers = new ArrayList<>();private String news;@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(news);}}public void setNews(String news) {this.news = news;notifyObservers();}
}public class NewsChannel implements Observer {private String name;public NewsChannel(String name) {this.name = name;}@Overridepublic void update(String news) {System.out.println(name + " received news: " + news);}
}
2. 策略模式
适用场景:
- 需要动态选择算法
- 算法族需要互换
- 避免使用多重条件判断
// 支付策略
public interface PaymentStrategy {void pay(double amount);
}public class CreditCardPayment implements PaymentStrategy {private String cardNumber;private String cvv;public CreditCardPayment(String cardNumber, String cvv) {this.cardNumber = cardNumber;this.cvv = cvv;}@Overridepublic void pay(double amount) {System.out.println("Paid " + amount + " using Credit Card");}
}public class PayPalPayment implements PaymentStrategy {private String email;public PayPalPayment(String email) {this.email = email;}@Overridepublic void pay(double amount) {System.out.println("Paid " + amount + " using PayPal");}
}public class PaymentContext {private PaymentStrategy strategy;public PaymentContext(PaymentStrategy strategy) {this.strategy = strategy;}public void executePayment(double amount) {strategy.pay(amount);}
}
3. 命令模式
适用场景:
- 需要撤销/重做操作
- 需要将请求排队
- 需要支持日志和事务
// 遥控器命令
public interface Command {void execute();void undo();
}public class Light {public void on() {System.out.println("Light is on");}public void off() {System.out.println("Light is off");}
}public class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.on();}@Overridepublic void undo() {light.off();}
}public class RemoteControl {private Command command;public void setCommand(Command command) {this.command = command;}public void pressButton() {command.execute();}public void pressUndo() {command.undo();}
}
设计模式重难点分析
创建型模式重难点
1. 单例模式
重难点:
- 线程安全:多线程环境下的实例创建
- 序列化:防止反序列化创建新实例
- 反射攻击:防止通过反射创建实例
- 内存泄漏:静态实例的生命周期管理
解决方案:
// 枚举单例(推荐)
public enum Singleton {INSTANCE;public void doSomething() {// 业务逻辑}
}// 双重检查锁定
public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}
2. 工厂模式
重难点:
- 简单工厂 vs 工厂方法:选择合适的工厂模式
- 抽象工厂的复杂性:管理多个产品族
- 扩展性:添加新产品时的修改成本
解决方案:
// 使用反射的通用工厂
public class GenericFactory<T> {private Map<String, Class<? extends T>> registeredClasses = new HashMap<>();public void registerClass(String type, Class<? extends T> clazz) {registeredClasses.put(type, clazz);}public T create(String type) {Class<? extends T> clazz = registeredClasses.get(type);if (clazz == null) {throw new IllegalArgumentException("Unknown type: " + type);}try {return clazz.getDeclaredConstructor().newInstance();} catch (Exception e) {throw new RuntimeException("Failed to create instance", e);}}
}
结构型模式重难点
1. 适配器模式
重难点:
- 类适配器 vs 对象适配器:选择合适的实现方式
- 接口设计:如何设计合适的适配器接口
- 性能影响:适配器可能带来的性能开销
解决方案:
// 对象适配器(推荐)
public class ObjectAdapter implements Target {private Adaptee adaptee;public ObjectAdapter(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic void request() {adaptee.specificRequest();}
}
2. 装饰器模式
重难点:
- 装饰器链:多个装饰器的组合使用
- 顺序问题:装饰器的应用顺序
- 性能考虑:装饰器链的性能影响
解决方案:
// 装饰器链管理
public class DecoratorChain {private List<Decorator> decorators = new ArrayList<>();public void addDecorator(Decorator decorator) {decorators.add(decorator);}public Component build(Component component) {Component result = component;for (Decorator decorator : decorators) {result = decorator.decorate(result);}return result;}
}
行为型模式重难点
1. 观察者模式
重难点:
- 内存泄漏:观察者未正确移除
- 通知顺序:多个观察者的通知顺序
- 异常处理:观察者处理异常时的策略
解决方案:
// 安全的观察者模式
public class SafeSubject implements Subject {private List<Observer> observers = new CopyOnWriteArrayList<>();@Overridepublic void notifyObservers() {for (Observer observer : observers) {try {observer.update();} catch (Exception e) {// 记录异常,不影响其他观察者System.err.println("Observer failed: " + e.getMessage());}}}
}
2. 策略模式
重难点:
- 策略选择:如何选择合适的策略
- 策略切换:运行时策略切换的复杂性
- 策略组合:多个策略的组合使用
解决方案:
// 策略选择器
public class StrategySelector {private Map<String, Strategy> strategies = new HashMap<>();public void registerStrategy(String key, Strategy strategy) {strategies.put(key, strategy);}public Strategy selectStrategy(String key) {Strategy strategy = strategies.get(key);if (strategy == null) {throw new IllegalArgumentException("Unknown strategy: " + key);}return strategy;}
}
设计模式在实际项目中的应用
Spring框架中的设计模式
1. 单例模式
// Spring Bean默认单例
@Component
public class UserService {// Spring容器管理单例
}// 配置单例
@Configuration
public class AppConfig {@Bean@Scope("singleton")public DataSource dataSource() {return new HikariDataSource();}
}
2. 工厂模式
// Spring的BeanFactory
@Configuration
public class PaymentConfig {@Beanpublic PaymentFactory paymentFactory() {return new PaymentFactory();}@Beanpublic PaymentService paymentService(PaymentFactory factory) {return new PaymentService(factory);}
}
3. 代理模式
// Spring AOP代理
@Service
public class UserService {@Transactionalpublic void saveUser(User user) {// 业务逻辑}@Cacheable("users")public User findById(Long id) {// 查询逻辑}
}
4. 观察者模式
// Spring事件机制
@Component
public class UserEventListener {@EventListenerpublic void handleUserCreated(UserCreatedEvent event) {// 处理用户创建事件}@EventListenerpublic void handleUserUpdated(UserUpdatedEvent event) {// 处理用户更新事件}
}// 发布事件
@Service
public class UserService {@Autowiredprivate ApplicationEventPublisher eventPublisher;public void createUser(User user) {// 创建用户逻辑eventPublisher.publishEvent(new UserCreatedEvent(user));}
}
微服务架构中的设计模式
1. 服务发现模式
// 服务注册
@SpringBootApplication
@EnableEurekaClient
public class UserServiceApplication {public static void main(String[] args) {SpringApplication.run(UserServiceApplication.class, args);}
}// 服务发现
@Service
public class OrderService {@Autowiredprivate DiscoveryClient discoveryClient;public List<ServiceInstance> getUserServiceInstances() {return discoveryClient.getInstances("user-service");}
}
2. 熔断器模式
// Hystrix熔断器
@Service
public class UserService {@HystrixCommand(fallbackMethod = "getUserFallback")public User getUser(Long id) {// 调用远程服务return userClient.getUser(id);}public User getUserFallback(Long id) {return new User(id, "Default User");}
}
3. 网关模式
// Spring Cloud Gateway
@Configuration
public class GatewayConfig {@Beanpublic RouteLocator customRouteLocator(RouteLocatorBuilder builder) {return builder.routes().route("user-service", r -> r.path("/api/users/**").uri("lb://user-service")).route("order-service", r -> r.path("/api/orders/**").uri("lb://order-service")).build();}
}
数据库操作中的设计模式
1. 仓储模式
// 通用仓储接口
public interface Repository<T, ID> {T save(T entity);Optional<T> findById(ID id);List<T> findAll();void deleteById(ID id);
}// 用户仓储
@Repository
public class UserRepository implements Repository<User, Long> {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic User save(User user) {// 保存用户逻辑return user;}@Overridepublic Optional<User> findById(Long id) {// 查询用户逻辑return Optional.empty();}
}
2. 工作单元模式
// 工作单元接口
public interface UnitOfWork {void registerNew(Object entity);void registerDirty(Object entity);void registerDeleted(Object entity);void commit();void rollback();
}// 工作单元实现
@Component
public class JpaUnitOfWork implements UnitOfWork {@Autowiredprivate EntityManager entityManager;private List<Object> newEntities = new ArrayList<>();private List<Object> dirtyEntities = new ArrayList<>();private List<Object> deletedEntities = new ArrayList<>();@Overridepublic void registerNew(Object entity) {newEntities.add(entity);}@Overridepublic void commit() {try {for (Object entity : newEntities) {entityManager.persist(entity);}for (Object entity : dirtyEntities) {entityManager.merge(entity);}for (Object entity : deletedEntities) {entityManager.remove(entity);}entityManager.getTransaction().commit();} catch (Exception e) {entityManager.getTransaction().rollback();throw e;}}
}
缓存设计中的设计模式
1. 装饰器模式
// 缓存装饰器
public class CachedUserService implements UserService {private final UserService userService;private final CacheManager cacheManager;public CachedUserService(UserService userService, CacheManager cacheManager) {this.userService = userService;this.cacheManager = cacheManager;}@Overridepublic User findById(Long id) {Cache cache = cacheManager.getCache("users");User user = cache.get(id, User.class);if (user == null) {user = userService.findById(id);cache.put(id, user);}return user;}
}
2. 策略模式
// 缓存策略
public interface CacheStrategy {void put(String key, Object value);Object get(String key);void evict(String key);
}// LRU缓存策略
public class LRUCacheStrategy implements CacheStrategy {private final Map<String, Object> cache = new LinkedHashMap<String, Object>(16, 0.75f, true) {@Overrideprotected boolean removeEldestEntry(Map.Entry<String, Object> eldest) {return size() > 1000;}};@Overridepublic synchronized void put(String key, Object value) {cache.put(key, value);}@Overridepublic synchronized Object get(String key) {return cache.get(key);}
}
设计模式最佳实践
1. 模式选择原则
何时使用设计模式
- 问题重复出现:相同问题多次遇到
- 代码结构复杂:需要更好的组织结构
- 团队协作:需要统一的代码规范
- 系统扩展:需要支持未来扩展
何时不使用设计模式
- 过度设计:简单问题不需要复杂模式
- 性能敏感:模式可能带来性能开销
- 团队不熟悉:团队对模式理解不够
- 项目时间紧张:没有足够时间设计
2. 模式组合使用
常见模式组合
// 工厂 + 单例 + 策略
public class PaymentProcessor {private static final PaymentProcessor INSTANCE = new PaymentProcessor();private final Map<String, PaymentStrategy> strategies = new HashMap<>();private PaymentProcessor() {// 注册策略strategies.put("credit", new CreditCardStrategy());strategies.put("paypal", new PayPalStrategy());}public static PaymentProcessor getInstance() {return INSTANCE;}public void processPayment(String type, double amount) {PaymentStrategy strategy = strategies.get(type);if (strategy != null) {strategy.pay(amount);} else {throw new IllegalArgumentException("Unknown payment type: " + type);}}
}
3. 反模式识别
常见反模式
- God Object:一个类承担过多职责
- Spaghetti Code:代码结构混乱
- Copy-Paste Programming:重复代码过多
- Golden Hammer:过度使用某个模式
解决方案
// 反模式:God Object
public class UserManager {public void createUser() { /* ... */ }public void updateUser() { /* ... */ }public void deleteUser() { /* ... */ }public void sendEmail() { /* ... */ }public void logActivity() { /* ... */ }public void generateReport() { /* ... */ }
}// 改进:职责分离
public class UserService {public void createUser() { /* ... */ }public void updateUser() { /* ... */ }public void deleteUser() { /* ... */ }
}public class EmailService {public void sendEmail() { /* ... */ }
}public class LoggingService {public void logActivity() { /* ... */ }
}public class ReportService {public void generateReport() { /* ... */ }
}
4. 性能考虑
模式性能影响
模式 | 性能影响 | 建议 |
---|---|---|
单例模式 | 低 | 推荐使用 |
工厂模式 | 低 | 推荐使用 |
装饰器模式 | 中 | 注意装饰器链长度 |
代理模式 | 中 | 考虑动态代理开销 |
观察者模式 | 中 | 注意观察者数量 |
策略模式 | 低 | 推荐使用 |
性能优化建议
// 对象池模式
public class ObjectPool<T> {private final Queue<T> pool = new ConcurrentLinkedQueue<>();private final Supplier<T> factory;private final int maxSize;public ObjectPool(Supplier<T> factory, int maxSize) {this.factory = factory;this.maxSize = maxSize;}public T acquire() {T object = pool.poll();if (object == null) {object = factory.get();}return object;}public void release(T object) {if (pool.size() < maxSize) {pool.offer(object);}}
}
总结
设计模式的核心价值
- 提高代码质量:使代码更加清晰、可维护、可扩展
- 解决常见问题:提供经过验证的解决方案
- 促进团队协作:建立统一的代码设计规范
- 降低学习成本:新团队成员更容易理解代码
学习建议
- 循序渐进:从简单模式开始,逐步学习复杂模式
- 实践为主:通过实际项目应用模式
- 理解原理:不仅要知道如何使用,更要理解为什么
- 避免过度使用:根据实际需要选择合适的模式
未来趋势
- 函数式编程模式:适应现代编程范式
- 响应式编程模式:处理异步和流式数据
- 微服务架构模式:支持分布式系统设计
- 云原生模式:适应云计算环境
设计模式是软件工程中的重要工具,掌握它们能够显著提高代码质量和开发效率。但记住,模式是工具,不是目的,应该根据实际需要合理使用。