Skip to content

设计模式

设计模式是在软件开发过程中,针对特定问题的可重用解决方案。它们是经过验证的最佳实践,可以帮助开发者编写更清晰、更可维护的代码。本章节将介绍Java中常用的设计模式。

什么是设计模式?

设计模式是软件开发中常见问题的典型解决方案。它们不是可以直接转换为代码的完整设计,而是描述了在特定情况下如何解决问题的方法。

设计模式的主要优点:

  1. 重用性:提供经过验证的解决方案
  2. 可维护性:使代码更清晰、更易于理解
  3. 沟通性:提供通用的术语来描述设计思路
  4. 扩展性:使系统更容易扩展和修改

设计模式分类

设计模式通常分为三类:

  1. 创建型模式:处理对象的创建过程
  2. 结构型模式:处理类或对象的组合
  3. 行为型模式:处理对象间职责的分配和通信

创建型模式

单例模式(Singleton Pattern)

单例模式确保一个类只有一个实例,并提供一个全局访问点。

java
public class Singleton {
    // 饿汉式
    private static final Singleton INSTANCE = new Singleton();
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

// 懒汉式(线程安全)
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;
    }
}

工厂模式(Factory Pattern)

工厂模式定义一个创建对象的接口,但由子类决定实例化哪个类。

java
// 产品接口
public interface Shape {
    void draw();
}

// 具体产品
public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("绘制圆形");
    }
}

public class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("绘制矩形");
    }
}

// 工厂类
public class ShapeFactory {
    public Shape createShape(String shapeType) {
        if (shapeType == null) {
            return null;
        }
        
        switch (shapeType.toLowerCase()) {
            case "circle":
                return new Circle();
            case "rectangle":
                return new Rectangle();
            default:
                return null;
        }
    }
}

// 使用示例
public class FactoryDemo {
    public static void main(String[] args) {
        ShapeFactory factory = new ShapeFactory();
        
        Shape shape1 = factory.createShape("circle");
        shape1.draw();
        
        Shape shape2 = factory.createShape("rectangle");
        shape2.draw();
    }
}

抽象工厂模式(Abstract Factory Pattern)

抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

java
// 抽象产品
public interface Button {
    void render();
}

public interface Checkbox {
    void check();
}

// 具体产品
public class WindowsButton implements Button {
    @Override
    public void render() {
        System.out.println("渲染Windows按钮");
    }
}

public class MacButton implements Button {
    @Override
    public void render() {
        System.out.println("渲染Mac按钮");
    }
}

public class WindowsCheckbox implements Checkbox {
    @Override
    public void check() {
        System.out.println("选中Windows复选框");
    }
}

public class MacCheckbox implements Checkbox {
    @Override
    public void check() {
        System.out.println("选中Mac复选框");
    }
}

// 抽象工厂
public interface GUIFactory {
    Button createButton();
    Checkbox createCheckbox();
}

// 具体工厂
public class WindowsFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }
    
    @Override
    public Checkbox createCheckbox() {
        return new WindowsCheckbox();
    }
}

public class MacFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new MacButton();
    }
    
    @Override
    public Checkbox createCheckbox() {
        return new MacCheckbox();
    }
}

// 客户端代码
public class Application {
    private Button button;
    private Checkbox checkbox;
    
    public Application(GUIFactory factory) {
        button = factory.createButton();
        checkbox = factory.createCheckbox();
    }
    
    public void paint() {
        button.render();
        checkbox.check();
    }
}

建造者模式(Builder Pattern)

建造者模式将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。

java
// 产品类
public class Computer {
    private String cpu;
    private String ram;
    private String storage;
    private String gpu;
    
    // 私有构造函数
    private Computer(Builder builder) {
        this.cpu = builder.cpu;
        this.ram = builder.ram;
        this.storage = builder.storage;
        this.gpu = builder.gpu;
    }
    
    // getter方法
    public String getCpu() { return cpu; }
    public String getRam() { return ram; }
    public String getStorage() { return storage; }
    public String getGpu() { return gpu; }
    
    // 静态内部类建造者
    public static class Builder {
        private String cpu;
        private String ram;
        private String storage;
        private String gpu;
        
        public Builder setCpu(String cpu) {
            this.cpu = cpu;
            return this;
        }
        
        public Builder setRam(String ram) {
            this.ram = ram;
            return this;
        }
        
        public Builder setStorage(String storage) {
            this.storage = storage;
            return this;
        }
        
        public Builder setGpu(String gpu) {
            this.gpu = gpu;
            return this;
        }
        
        public Computer build() {
            return new Computer(this);
        }
    }
    
    @Override
    public String toString() {
        return "Computer{" +
                "cpu='" + cpu + '\'' +
                ", ram='" + ram + '\'' +
                ", storage='" + storage + '\'' +
                ", gpu='" + gpu + '\'' +
                '}';
    }
}

// 使用示例
public class BuilderDemo {
    public static void main(String[] args) {
        Computer gamingComputer = new Computer.Builder()
                .setCpu("Intel i9")
                .setRam("32GB")
                .setStorage("1TB SSD")
                .setGpu("RTX 4090")
                .build();
        
        System.out.println(gamingComputer);
        
        Computer officeComputer = new Computer.Builder()
                .setCpu("Intel i5")
                .setRam("16GB")
                .setStorage("512GB SSD")
                .build();
        
        System.out.println(officeComputer);
    }
}

结构型模式

适配器模式(Adapter Pattern)

适配器模式将一个类的接口转换成客户希望的另一个接口。

java
// 目标接口
public interface MediaPlayer {
    void play(String audioType, String fileName);
}

// 被适配者
public class Mp3Player {
    public void playMp3(String fileName) {
        System.out.println("播放MP3文件: " + fileName);
    }
}

public class VlcPlayer {
    public void playVlc(String fileName) {
        System.out.println("播放VLC文件: " + fileName);
    }
}

// 适配器
public class MediaAdapter implements MediaPlayer {
    private Mp3Player mp3Player;
    private VlcPlayer vlcPlayer;
    
    public MediaAdapter(String audioType) {
        if ("mp3".equalsIgnoreCase(audioType)) {
            mp3Player = new Mp3Player();
        } else if ("vlc".equalsIgnoreCase(audioType)) {
            vlcPlayer = new VlcPlayer();
        }
    }
    
    @Override
    public void play(String audioType, String fileName) {
        if ("mp3".equalsIgnoreCase(audioType)) {
            mp3Player.playMp3(fileName);
        } else if ("vlc".equalsIgnoreCase(audioType)) {
            vlcPlayer.playVlc(fileName);
        }
    }
}

// 适配器客户端
public class AudioPlayer implements MediaPlayer {
    MediaAdapter mediaAdapter;
    
    @Override
    public void play(String audioType, String fileName) {
        // 内置支持MP3
        if ("mp3".equalsIgnoreCase(audioType)) {
            System.out.println("播放MP3文件: " + fileName);
        }
        // 适配支持其他格式
        else if ("vlc".equalsIgnoreCase(audioType)) {
            mediaAdapter = new MediaAdapter(audioType);
            mediaAdapter.play(audioType, fileName);
        } else {
            System.out.println("不支持的音频格式: " + audioType);
        }
    }
}

// 使用示例
public class AdapterDemo {
    public static void main(String[] args) {
        AudioPlayer audioPlayer = new AudioPlayer();
        
        audioPlayer.play("mp3", "song.mp3");
        audioPlayer.play("vlc", "movie.vlc");
        audioPlayer.play("mp4", "video.mp4");
    }
}

装饰器模式(Decorator Pattern)

装饰器模式动态地给一个对象添加一些额外的职责。

java
// 组件接口
public interface Coffee {
    String getDescription();
    double getCost();
}

// 具体组件
public class SimpleCoffee implements Coffee {
    @Override
    public String getDescription() {
        return "简单咖啡";
    }
    
    @Override
    public double getCost() {
        return 2.0;
    }
}

// 装饰器抽象类
public abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;
    
    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
    
    @Override
    public String getDescription() {
        return coffee.getDescription();
    }
    
    @Override
    public double getCost() {
        return coffee.getCost();
    }
}

// 具体装饰器
public class Milk extends CoffeeDecorator {
    public Milk(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDescription() {
        return coffee.getDescription() + ", 加牛奶";
    }
    
    @Override
    public double getCost() {
        return coffee.getCost() + 0.5;
    }
}

public class Sugar extends CoffeeDecorator {
    public Sugar(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public String getDescription() {
        return coffee.getDescription() + ", 加糖";
    }
    
    @Override
    public double getCost() {
        return coffee.getCost() + 0.3;
    }
}

// 使用示例
public class DecoratorDemo {
    public static void main(String[] args) {
        Coffee coffee = new SimpleCoffee();
        System.out.println(coffee.getDescription() + " - $" + coffee.getCost());
        
        coffee = new Milk(coffee);
        System.out.println(coffee.getDescription() + " - $" + coffee.getCost());
        
        coffee = new Sugar(coffee);
        System.out.println(coffee.getDescription() + " - $" + coffee.getCost());
    }
}

代理模式(Proxy Pattern)

代理模式为其他对象提供一个代理以控制对这个对象的访问。

java
// 接口
public interface Image {
    void display();
}

// 真实对象
public class RealImage implements Image {
    private String fileName;
    
    public RealImage(String fileName) {
        this.fileName = fileName;
        loadFromDisk();
    }
    
    private void loadFromDisk() {
        System.out.println("从磁盘加载 " + fileName);
    }
    
    @Override
    public void display() {
        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 ProxyDemo {
    public static void main(String[] args) {
        Image image = new ProxyImage("test.jpg");
        
        // 图像将从磁盘加载
        image.display();
        System.out.println("---");
        
        // 图像不需要从磁盘加载
        image.display();
    }
}

行为型模式

观察者模式(Observer Pattern)

观察者模式定义了对象之间的一对多依赖关系,当一个对象改变状态时,所有依赖它的对象都会收到通知并自动更新。

java
import java.util.ArrayList;
import java.util.List;

// 观察者接口
public interface Observer {
    void update(String message);
}

// 主题接口
public interface Subject {
    void addObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers(String message);
}

// 具体主题
public class NewsAgency implements Subject {
    private List<Observer> observers;
    private String news;
    
    public NewsAgency() {
        observers = new ArrayList<>();
    }
    
    @Override
    public void addObserver(Observer observer) {
        observers.add(observer);
    }
    
    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
    
    @Override
    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
    
    public void setNews(String news) {
        this.news = news;
        notifyObservers(news);
    }
}

// 具体观察者
public class NewsChannel implements Observer {
    private String name;
    
    public NewsChannel(String name) {
        this.name = name;
    }
    
    @Override
    public void update(String message) {
        System.out.println(name + " 收到新闻: " + message);
    }
}

// 使用示例
public class ObserverDemo {
    public static void main(String[] args) {
        NewsAgency agency = new NewsAgency();
        
        NewsChannel channel1 = new NewsChannel("新闻频道1");
        NewsChannel channel2 = new NewsChannel("新闻频道2");
        
        agency.addObserver(channel1);
        agency.addObserver(channel2);
        
        agency.setNews("重大新闻:设计模式教程发布!");
    }
}

策略模式(Strategy Pattern)

策略模式定义了一系列算法,将每个算法封装起来,并使它们可以互相替换。

java
// 策略接口
public interface PaymentStrategy {
    void pay(int amount);
}

// 具体策略
public class CreditCardStrategy implements PaymentStrategy {
    private String name;
    private String cardNumber;
    
    public CreditCardStrategy(String name, String cardNumber) {
        this.name = name;
        this.cardNumber = cardNumber;
    }
    
    @Override
    public void pay(int amount) {
        System.out.println(amount + " 元通过信用卡支付");
    }
}

public class PayPalStrategy implements PaymentStrategy {
    private String email;
    
    public PayPalStrategy(String email) {
        this.email = email;
    }
    
    @Override
    public void pay(int amount) {
        System.out.println(amount + " 元通过PayPal支付");
    }
}

// 上下文
public class ShoppingCart {
    private PaymentStrategy paymentStrategy;
    
    public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }
    
    public void checkout(int amount) {
        if (paymentStrategy != null) {
            paymentStrategy.pay(amount);
        } else {
            System.out.println("请选择支付方式");
        }
    }
}

// 使用示例
public class StrategyDemo {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();
        
        // 使用信用卡支付
        cart.setPaymentStrategy(new CreditCardStrategy("张三", "123456789"));
        cart.checkout(100);
        
        // 使用PayPal支付
        cart.setPaymentStrategy(new PayPalStrategy("zhangsan@example.com"));
        cart.checkout(200);
    }
}

模板方法模式(Template Method Pattern)

模板方法模式定义一个操作中的算法骨架,而将一些步骤延迟到子类中。

java
// 抽象类
public abstract class Game {
    // 模板方法
    public final void play() {
        // 初始化游戏
        initialize();
        
        // 开始游戏
        startPlay();
        
        // 结束游戏
        endPlay();
    }
    
    // 具体方法
    protected void initialize() {
        System.out.println("游戏初始化");
    }
    
    // 抽象方法,由子类实现
    protected abstract void startPlay();
    
    // 钩子方法,子类可选择性重写
    protected void endPlay() {
        System.out.println("游戏结束");
    }
}

// 具体实现
public class Cricket extends Game {
    @Override
    protected void startPlay() {
        System.out.println("板球游戏开始");
    }
    
    @Override
    protected void endPlay() {
        System.out.println("板球游戏结束");
    }
}

public class Football extends Game {
    @Override
    protected void startPlay() {
        System.out.println("足球游戏开始");
    }
    
    @Override
    protected void endPlay() {
        System.out.println("足球游戏结束");
    }
}

// 使用示例
public class TemplateMethodDemo {
    public static void main(String[] args) {
        Game game = new Cricket();
        game.play();
        System.out.println();
        
        game = new Football();
        game.play();
    }
}

实践练习

  1. 实现一个简单的日志系统,使用单例模式确保只有一个日志实例
  2. 创建一个图形绘制系统,使用工厂模式创建不同类型的图形
  3. 设计一个咖啡店系统,使用装饰器模式为咖啡添加不同的配料
  4. 实现一个新闻发布系统,使用观察者模式通知订阅者
  5. 创建一个支付系统,使用策略模式支持多种支付方式

总结

设计模式是软件开发中的重要概念,它们提供了经过验证的解决方案来解决常见的设计问题。通过学习和应用设计模式,我们可以:

  1. 编写出更加灵活和可维护的代码
  2. 提高代码的可重用性
  3. 改善团队之间的沟通
  4. 更好地理解和使用现有的框架和库

在实际开发中,我们应该根据具体问题选择合适的设计模式,避免过度设计。设计模式不是万能的,它们只是工具,正确使用才能发挥最大价值。