# 🚀 Java高级面试题:设计模式

84 阅读11分钟

💡 面试官最爱问的经典问题之一! 掌握设计模式,让你在面试中脱颖而出!

📋 问题描述

请详细解释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() {
        // 团队熟悉的设计模式优先
        // 避免使用团队不熟悉的高级模式
        // 提供必要的培训和文档
    }
}

🎉 总结

🏆 恭喜你! 你已经掌握了设计模式的核心知识!

设计模式是软件设计的重要工具。理解各种设计模式的特点、应用场景和实现方式,掌握在实际项目中正确使用设计模式的方法,是成为优秀软件工程师的关键。

💪 掌握这些知识,让你在面试中更有信心!

🎯 面试要点

📝 面试官最爱问的问题,必须掌握!

  1. 🏗️ 创建型模式:掌握单例、工厂、建造者等模式
  2. 🔧 结构型模式:理解适配器、装饰器、代理等模式
  3. 🎭 行为型模式:掌握观察者、策略、命令等模式
  4. 🎯 应用场景:了解各种模式的实际应用场景
  5. ⚖️ 优缺点分析:能够分析各种模式的优缺点
  6. 🔧 实际应用:能够在项目中正确使用设计模式
  7. ⚠️ 注意事项:避免过度设计和模式滥用

🎯 面试加分项:能够结合实际项目经验,说明设计模式的具体应用!

📚 扩展阅读

📖 深入学习,成为设计模式专家!

  • 📘 《设计模式:可复用面向对象软件的基础》
  • 📘 《Head First设计模式》
  • 🌐 设计模式最佳实践
  • 🛠️ 设计模式在框架中的应用

💡 记住:设计模式是工具,不是目的,要根据实际需求选择合适的模式!

🚀 加油! 下一个设计模式专家就是你!