💡 面试官最爱问的经典问题之一! 掌握设计模式,让你在面试中脱颖而出!
📋 问题描述
请详细解释Java中常用的设计模式,包括创建型、结构型、行为型设计模式。每种设计模式的应用场景、优缺点,以及如何在实际项目中正确使用设计模式。如何避免过度设计?
⚠️ 面试提示:这个问题考察的是设计模式的深度理解,需要从基础概念到实际应用都要掌握!
🎯 详细解答
1. 🏗️ 设计模式概述
🎨 记忆技巧:设计模式就像建筑设计的经典模板,可以解决常见的软件设计问题!
设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它描述了在软件设计过程中一些不断重复发生的问题,以及该问题的解决方案。
🏠 通俗比喻:设计模式就像烹饪的经典菜谱,每种菜谱都有固定的步骤和配料,但可以根据具体情况进行调整,做出美味的菜肴。
1.1 设计模式的分类
- 🏗️ 创建型模式:关注对象的创建过程
- 🔧 结构型模式:关注类和对象的组合
- 🎭 行为型模式:关注对象间的通信和职责分配
1.2 设计模式的原则
- 🎯 单一职责原则:一个类只有一个变化的原因
- 🔄 开闭原则:对扩展开放,对修改关闭
- 🔄 里氏替换原则:子类可以替换父类
- 🔗 接口隔离原则:使用多个专门的接口
- 📦 依赖倒置原则:依赖抽象而不是具体
2. 🏗️ 创建型设计模式
🎯 对象创建:创建型模式关注对象的创建过程!
2.1 单例模式 (Singleton)
// 单例模式实现
public class Singleton {
// 1. 饿汉式单例
public class EagerSingleton {
private static final EagerSingleton INSTANCE = new EagerSingleton();
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return INSTANCE;
}
}
// 2. 懒汉式单例(线程安全)
public class LazySingleton {
private static volatile LazySingleton instance;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
if (instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
}
// 3. 枚举单例(推荐)
public enum EnumSingleton {
INSTANCE;
public void doSomething() {
System.out.println("枚举单例方法");
}
}
// 4. 静态内部类单例
public class StaticInnerClassSingleton {
private StaticInnerClassSingleton() {}
private static class SingletonHolder {
private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();
}
public static StaticInnerClassSingleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
}
🏠 通俗比喻:单例模式就像公司的CEO,整个公司只能有一个CEO,所有人都通过同一个CEO来管理公司。
✨ 应用场景:
- 数据库连接池
- 配置管理器
- 日志记录器
- 缓存管理器
2.2 工厂模式 (Factory)
// 工厂模式实现
public class FactoryPattern {
// 1. 简单工厂模式
public class SimpleFactory {
public static Product createProduct(String type) {
switch (type) {
case "A":
return new ProductA();
case "B":
return new ProductB();
default:
throw new IllegalArgumentException("未知产品类型: " + type);
}
}
}
// 2. 工厂方法模式
public abstract class ProductFactory {
public abstract Product createProduct();
public void doSomething() {
Product product = createProduct();
product.use();
}
}
public class ProductAFactory extends ProductFactory {
@Override
public Product createProduct() {
return new ProductA();
}
}
public class ProductBFactory extends ProductFactory {
@Override
public Product createProduct() {
return new ProductB();
}
}
// 3. 抽象工厂模式
public abstract class AbstractFactory {
public abstract Product createProduct();
public abstract Service createService();
}
public class ConcreteFactory1 extends AbstractFactory {
@Override
public Product createProduct() {
return new ProductA();
}
@Override
public Service createService() {
return new ServiceA();
}
}
}
🏠 通俗比喻:工厂模式就像汽车工厂,根据订单生产不同类型的汽车,客户不需要知道汽车的具体制造过程。
2.3 建造者模式 (Builder)
// 建造者模式实现
public class BuilderPattern {
// 产品类
public class Computer {
private String cpu;
private String memory;
private String storage;
private String graphics;
private Computer(Builder builder) {
this.cpu = builder.cpu;
this.memory = builder.memory;
this.storage = builder.storage;
this.graphics = builder.graphics;
}
// 建造者
public static class Builder {
private String cpu;
private String memory;
private String storage;
private String graphics;
public Builder setCpu(String cpu) {
this.cpu = cpu;
return this;
}
public Builder setMemory(String memory) {
this.memory = memory;
return this;
}
public Builder setStorage(String storage) {
this.storage = storage;
return this;
}
public Builder setGraphics(String graphics) {
this.graphics = graphics;
return this;
}
public Computer build() {
return new Computer(this);
}
}
}
// 使用示例
public class ComputerBuilderExample {
public void buildComputer() {
Computer computer = new Computer.Builder()
.setCpu("Intel i7")
.setMemory("16GB")
.setStorage("512GB SSD")
.setGraphics("RTX 3080")
.build();
}
}
}
🏠 通俗比喻:建造者模式就像定制房屋,你可以选择不同的材料、风格、大小,最终建造出符合你需求的房子。
3. 🔧 结构型设计模式
🎯 对象组合:结构型模式关注类和对象的组合!
3.1 适配器模式 (Adapter)
// 适配器模式实现
public class AdapterPattern {
// 目标接口
public interface MediaPlayer {
void play(String audioType, String fileName);
}
// 被适配的类
public class Mp4Player {
public void playMp4(String fileName) {
System.out.println("播放Mp4文件: " + fileName);
}
}
public class VlcPlayer {
public void playVlc(String fileName) {
System.out.println("播放Vlc文件: " + fileName);
}
}
// 适配器
public class MediaAdapter implements MediaPlayer {
private Mp4Player mp4Player;
private VlcPlayer vlcPlayer;
public MediaAdapter(String audioType) {
if (audioType.equalsIgnoreCase("mp4")) {
mp4Player = new Mp4Player();
} else if (audioType.equalsIgnoreCase("vlc")) {
vlcPlayer = new VlcPlayer();
}
}
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("mp4")) {
mp4Player.playMp4(fileName);
} else if (audioType.equalsIgnoreCase("vlc")) {
vlcPlayer.playVlc(fileName);
}
}
}
// 客户端
public class AudioPlayer implements MediaPlayer {
private MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("mp3")) {
System.out.println("播放Mp3文件: " + fileName);
} else if (audioType.equalsIgnoreCase("mp4") || audioType.equalsIgnoreCase("vlc")) {
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
} else {
System.out.println("不支持的音频格式: " + audioType);
}
}
}
}
🏠 通俗比喻:适配器模式就像电源适配器,让不同国家的电器能够使用同一个插座。
3.2 装饰器模式 (Decorator)
// 装饰器模式实现
public class DecoratorPattern {
// 抽象组件
public abstract class Coffee {
public abstract String getDescription();
public abstract double getCost();
}
// 具体组件
public class SimpleCoffee extends Coffee {
@Override
public String getDescription() {
return "简单咖啡";
}
@Override
public double getCost() {
return 10.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);
}
@Override
public String getDescription() {
return coffee.getDescription() + ", 加牛奶";
}
@Override
public double getCost() {
return coffee.getCost() + 2.0;
}
}
public class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) {
super(coffee);
}
@Override
public String getDescription() {
return coffee.getDescription() + ", 加糖";
}
@Override
public double getCost() {
return coffee.getCost() + 1.0;
}
}
// 使用示例
public class CoffeeShop {
public void makeCoffee() {
Coffee coffee = new SimpleCoffee();
System.out.println(coffee.getDescription() + " - 价格: " + coffee.getCost());
coffee = new MilkDecorator(coffee);
System.out.println(coffee.getDescription() + " - 价格: " + coffee.getCost());
coffee = new SugarDecorator(coffee);
System.out.println(coffee.getDescription() + " - 价格: " + coffee.getCost());
}
}
}
🏠 通俗比喻:装饰器模式就像给蛋糕加装饰,可以一层一层地添加奶油、水果、巧克力等装饰,最终做出漂亮的蛋糕。
3.3 代理模式 (Proxy)
// 代理模式实现
public class ProxyPattern {
// 抽象主题
public interface Image {
void display();
}
// 真实主题
public class RealImage implements Image {
private String fileName;
public RealImage(String fileName) {
this.fileName = fileName;
loadFromDisk(fileName);
}
@Override
public void display() {
System.out.println("显示图片: " + fileName);
}
private void loadFromDisk(String fileName) {
System.out.println("从磁盘加载图片: " + fileName);
}
}
// 代理类
public class ProxyImage implements Image {
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName) {
this.fileName = fileName;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(fileName);
}
realImage.display();
}
}
// 使用示例
public class ImageViewer {
public void viewImage() {
Image image = new ProxyImage("test.jpg");
// 第一次显示,需要加载
image.display();
// 第二次显示,直接使用缓存
image.display();
}
}
}
🏠 通俗比喻:代理模式就像明星的经纪人,客户想见明星时,先通过经纪人,经纪人决定是否让客户见明星,以及如何安排见面。
4. 🎭 行为型设计模式
🎯 对象交互:行为型模式关注对象间的通信和职责分配!
4.1 观察者模式 (Observer)
// 观察者模式实现
public class ObserverPattern {
// 观察者接口
public interface Observer {
void update(String message);
}
// 具体观察者
public class EmailObserver implements Observer {
private String email;
public EmailObserver(String email) {
this.email = email;
}
@Override
public void update(String message) {
System.out.println("发送邮件到 " + email + ": " + message);
}
}
public class SMSObserver implements Observer {
private String phone;
public SMSObserver(String phone) {
this.phone = phone;
}
@Override
public void update(String message) {
System.out.println("发送短信到 " + phone + ": " + message);
}
}
// 主题接口
public interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyObservers();
}
// 具体主题
public class NewsAgency implements Subject {
private List<Observer> observers = new ArrayList<>();
private String news;
@Override
public void attach(Observer observer) {
observers.add(observer);
}
@Override
public void detach(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(news);
}
}
public void setNews(String news) {
this.news = news;
notifyObservers();
}
}
// 使用示例
public class NewsSystem {
public void broadcastNews() {
NewsAgency agency = new NewsAgency();
agency.attach(new EmailObserver("user@example.com"));
agency.attach(new SMSObserver("1234567890"));
agency.setNews("重要新闻:今天天气很好!");
}
}
}
🏠 通俗比喻:观察者模式就像新闻订阅,当你订阅了某个新闻频道,每当有新闻发布时,你都会收到通知。
4.2 策略模式 (Strategy)
// 策略模式实现
public class StrategyPattern {
// 策略接口
public interface PaymentStrategy {
void pay(double amount);
}
// 具体策略
public class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
public CreditCardPayment(String cardNumber) {
this.cardNumber = cardNumber;
}
@Override
public void pay(double amount) {
System.out.println("使用信用卡支付: " + amount + " 元");
}
}
public class PayPalPayment implements PaymentStrategy {
private String email;
public PayPalPayment(String email) {
this.email = email;
}
@Override
public void pay(double amount) {
System.out.println("使用PayPal支付: " + amount + " 元");
}
}
public class AlipayPayment implements PaymentStrategy {
private String account;
public AlipayPayment(String account) {
this.account = account;
}
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付: " + amount + " 元");
}
}
// 上下文类
public class PaymentContext {
private PaymentStrategy strategy;
public PaymentContext(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void setStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void executePayment(double amount) {
strategy.pay(amount);
}
}
// 使用示例
public class ShoppingCart {
public void checkout(String paymentMethod, double amount) {
PaymentContext context;
switch (paymentMethod) {
case "credit":
context = new PaymentContext(new CreditCardPayment("1234-5678-9012-3456"));
break;
case "paypal":
context = new PaymentContext(new PayPalPayment("user@example.com"));
break;
case "alipay":
context = new PaymentContext(new AlipayPayment("user@alipay.com"));
break;
default:
throw new IllegalArgumentException("不支持的支付方式");
}
context.executePayment(amount);
}
}
}
🏠 通俗比喻:策略模式就像选择交通工具,你可以选择汽车、飞机、火车等不同的方式到达目的地,每种方式都有不同的特点。
4.3 命令模式 (Command)
// 命令模式实现
public class CommandPattern {
// 命令接口
public interface Command {
void execute();
void undo();
}
// 具体命令
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
@Override
public void undo() {
light.turnOff();
}
}
public class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOff();
}
@Override
public void undo() {
light.turnOn();
}
}
// 接收者
public class Light {
public void turnOn() {
System.out.println("灯亮了");
}
public void turnOff() {
System.out.println("灯灭了");
}
}
// 调用者
public class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
public void pressUndoButton() {
command.undo();
}
}
// 使用示例
public class SmartHome {
public void controlLight() {
Light light = new Light();
RemoteControl remote = new RemoteControl();
// 开灯
remote.setCommand(new LightOnCommand(light));
remote.pressButton();
// 关灯
remote.setCommand(new LightOffCommand(light));
remote.pressButton();
// 撤销
remote.pressUndoButton();
}
}
}
🏠 通俗比喻:命令模式就像遥控器,你按下按钮时,遥控器发送命令给电器,电器执行相应的操作。
5. 🎯 设计模式应用场景
🎯 实际应用:设计模式在实际项目中的应用!
5.1 Spring框架中的设计模式
// Spring中的设计模式应用
public class SpringDesignPatterns {
// 1. 单例模式 - Spring Bean默认单例
@Component
public class UserService {
// Spring容器中默认是单例
}
// 2. 工厂模式 - BeanFactory
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserService();
}
}
// 3. 代理模式 - AOP
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("方法执行前: " + joinPoint.getSignature().getName());
}
}
// 4. 观察者模式 - 事件监听
@EventListener
public void handleUserCreated(UserCreatedEvent event) {
System.out.println("用户创建事件: " + event.getUser());
}
// 5. 策略模式 - 支付策略
public interface PaymentStrategy {
void pay(double amount);
}
@Component("creditCardPayment")
public class CreditCardPayment implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("信用卡支付: " + amount);
}
}
}
5.2 实际项目中的应用
// 实际项目中的设计模式应用
public class RealWorldExamples {
// 1. 数据库连接池 - 单例模式
public class DatabaseConnectionPool {
private static volatile DatabaseConnectionPool instance;
private List<Connection> connections;
private DatabaseConnectionPool() {
connections = new ArrayList<>();
}
public static DatabaseConnectionPool getInstance() {
if (instance == null) {
synchronized (DatabaseConnectionPool.class) {
if (instance == null) {
instance = new DatabaseConnectionPool();
}
}
}
return instance;
}
}
// 2. 缓存策略 - 策略模式
public interface CacheStrategy {
void put(String key, Object value);
Object get(String key);
}
public class RedisCacheStrategy implements CacheStrategy {
@Override
public void put(String key, Object value) {
// Redis缓存实现
}
@Override
public Object get(String key) {
// Redis缓存获取
return null;
}
}
public class MemoryCacheStrategy implements CacheStrategy {
private Map<String, Object> cache = new HashMap<>();
@Override
public void put(String key, Object value) {
cache.put(key, value);
}
@Override
public Object get(String key) {
return cache.get(key);
}
}
// 3. 消息通知 - 观察者模式
public class OrderService {
private List<OrderObserver> observers = new ArrayList<>();
public void addObserver(OrderObserver observer) {
observers.add(observer);
}
public void createOrder(Order order) {
// 创建订单逻辑
notifyObservers(order);
}
private void notifyObservers(Order order) {
for (OrderObserver observer : observers) {
observer.onOrderCreated(order);
}
}
}
}
6. ⚠️ 设计模式注意事项
🎯 最佳实践:设计模式使用的最佳实践!
6.1 避免过度设计
// 过度设计的例子
public class OverDesignExample {
// ❌ 过度设计:为简单的字符串操作使用策略模式
public interface StringProcessor {
String process(String input);
}
public class UpperCaseProcessor implements StringProcessor {
@Override
public String process(String input) {
return input.toUpperCase();
}
}
public class LowerCaseProcessor implements StringProcessor {
@Override
public String process(String input) {
return input.toLowerCase();
}
}
// ✅ 简单设计:直接使用方法
public class SimpleStringProcessor {
public String toUpperCase(String input) {
return input.toUpperCase();
}
public String toLowerCase(String input) {
return input.toLowerCase();
}
}
}
6.2 设计模式选择原则
// 设计模式选择原则
public class DesignPatternSelection {
// 1. 根据问题选择模式
public void selectPatternByProblem() {
// 需要创建复杂对象 -> 建造者模式
// 需要统一接口 -> 适配器模式
// 需要动态添加功能 -> 装饰器模式
// 需要解耦发送者和接收者 -> 命令模式
}
// 2. 考虑维护成本
public void considerMaintenanceCost() {
// 简单问题用简单方案
// 复杂问题用设计模式
// 平衡代码复杂度和可维护性
}
// 3. 团队技能水平
public void considerTeamSkill() {
// 团队熟悉的设计模式优先
// 避免使用团队不熟悉的高级模式
// 提供必要的培训和文档
}
}
🎉 总结
🏆 恭喜你! 你已经掌握了设计模式的核心知识!
设计模式是软件设计的重要工具。理解各种设计模式的特点、应用场景和实现方式,掌握在实际项目中正确使用设计模式的方法,是成为优秀软件工程师的关键。
💪 掌握这些知识,让你在面试中更有信心!
🎯 面试要点
📝 面试官最爱问的问题,必须掌握!
- 🏗️ 创建型模式:掌握单例、工厂、建造者等模式
- 🔧 结构型模式:理解适配器、装饰器、代理等模式
- 🎭 行为型模式:掌握观察者、策略、命令等模式
- 🎯 应用场景:了解各种模式的实际应用场景
- ⚖️ 优缺点分析:能够分析各种模式的优缺点
- 🔧 实际应用:能够在项目中正确使用设计模式
- ⚠️ 注意事项:避免过度设计和模式滥用
🎯 面试加分项:能够结合实际项目经验,说明设计模式的具体应用!
📚 扩展阅读
📖 深入学习,成为设计模式专家!
- 📘 《设计模式:可复用面向对象软件的基础》
- 📘 《Head First设计模式》
- 🌐 设计模式最佳实践
- 🛠️ 设计模式在框架中的应用
💡 记住:设计模式是工具,不是目的,要根据实际需求选择合适的模式!
🚀 加油! 下一个设计模式专家就是你!