设计模式
设计模式是在软件开发过程中,针对特定问题的可重用解决方案。它们是经过验证的最佳实践,可以帮助开发者编写更清晰、更可维护的代码。本章节将介绍Java中常用的设计模式。
什么是设计模式?
设计模式是软件开发中常见问题的典型解决方案。它们不是可以直接转换为代码的完整设计,而是描述了在特定情况下如何解决问题的方法。
设计模式的主要优点:
- 重用性:提供经过验证的解决方案
- 可维护性:使代码更清晰、更易于理解
- 沟通性:提供通用的术语来描述设计思路
- 扩展性:使系统更容易扩展和修改
设计模式分类
设计模式通常分为三类:
- 创建型模式:处理对象的创建过程
- 结构型模式:处理类或对象的组合
- 行为型模式:处理对象间职责的分配和通信
创建型模式
单例模式(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();
}
}实践练习
- 实现一个简单的日志系统,使用单例模式确保只有一个日志实例
- 创建一个图形绘制系统,使用工厂模式创建不同类型的图形
- 设计一个咖啡店系统,使用装饰器模式为咖啡添加不同的配料
- 实现一个新闻发布系统,使用观察者模式通知订阅者
- 创建一个支付系统,使用策略模式支持多种支付方式
总结
设计模式是软件开发中的重要概念,它们提供了经过验证的解决方案来解决常见的设计问题。通过学习和应用设计模式,我们可以:
- 编写出更加灵活和可维护的代码
- 提高代码的可重用性
- 改善团队之间的沟通
- 更好地理解和使用现有的框架和库
在实际开发中,我们应该根据具体问题选择合适的设计模式,避免过度设计。设计模式不是万能的,它们只是工具,正确使用才能发挥最大价值。