目录
引言
设计模式是软件开发中经过验证的、用于解决特定问题的解决方案。它们代表了软件设计领域的最佳实践,是众多开发者经验的结晶。在Java开发中,合理运用设计模式可以提高代码的可读性、可维护性和可扩展性,同时降低系统的复杂度。
本文将详细介绍GoF(Gang of Four,四人帮)提出的23种经典设计模式在Java项目中的实际应用案例,帮助读者理解如何在实际项目中灵活运用这些模式来解决具体问题。
创建型模式
创建型模式关注对象的创建过程,试图将对象的创建与使用分离,使系统更加灵活。
单例模式
定义:确保一个类只有一个实例,并提供一个全局访问点。
实际应用:数据库连接池、线程池、配置管理器等。
代码示例:使用双重检查锁定实现线程安全的单例
public class DatabaseConnectionPool {
private static volatile DatabaseConnectionPool instance;
private List<Connection> connectionPool;
private DatabaseConnectionPool() {
// 初始化连接池
connectionPool = new ArrayList<>();
// 创建初始连接
for (int i = 0; i < 10; i++) {
connectionPool.add(createNewConnection());
}
}
public static DatabaseConnectionPool getInstance() {
if (instance == null) {
synchronized (DatabaseConnectionPool.class) {
if (instance == null) {
instance = new DatabaseConnectionPool();
}
}
}
return instance;
}
private Connection createNewConnection() {
// 创建数据库连接的代码
return null; // 实际项目中返回真实连接
}
public synchronized Connection getConnection() {
if (connectionPool.isEmpty()) {
connectionPool.add(createNewConnection());
}
Connection connection = connectionPool.remove(connectionPool.size() - 1);
return connection;
}
public synchronized void releaseConnection(Connection connection) {
connectionPool.add(connection);
}
}
优点:
- 节省系统资源,避免重复创建对象
- 提供统一访问点,便于协调系统整体行为
缺点:
- 单例类职责过重,违背单一职责原则
- 扩展困难,若要扩展单例类,只能修改原有代码
工厂方法模式
定义:定义一个创建对象的接口,但由子类决定实例化的类。工厂方法使一个类的实例化延迟到其子类。
实际应用:日志记录器、数据访问对象(DAO)、UI控件创建等。
代码示例:支付系统中的支付方式工厂
// 支付接口
public interface Payment {
void pay(double amount);
}
// 具体支付实现:支付宝
public class AliPay implements Payment {
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付:" + amount + "元");
// 实际支付逻辑
}
}
// 具体支付实现:微信支付
public class WeChatPay implements Payment {
@Override
public void pay(double amount) {
System.out.println("使用微信支付:" + amount + "元");
// 实际支付逻辑
}
}
// 支付工厂接口
public interface PaymentFactory {
Payment createPayment();
}
// 支付宝工厂
public class AliPayFactory implements PaymentFactory {
@Override
public Payment createPayment() {
return new AliPay();
}
}
// 微信支付工厂
public class WeChatPayFactory implements PaymentFactory {
@Override
public Payment createPayment() {
return new WeChatPay();
}
}
// 客户端代码
public class PaymentService {
public void processPayment(String paymentType, double amount) {
PaymentFactory factory = null;
if ("alipay".equals(paymentType)) {
factory = new AliPayFactory();
} else if ("wechat".equals(paymentType)) {
factory = new WeChatPayFactory();
} else {
throw new IllegalArgumentException("不支持的支付方式");
}
Payment payment = factory.createPayment();
payment.pay(amount);
}
}
优点:
- 符合开闭原则,新增产品只需添加新的工厂类
- 符合单一职责原则,每个工厂只负责创建对应的产品
缺点:
- 类的个数增加,增加系统复杂度
- 增加了系统的抽象性和理解难度
抽象工厂模式
定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
实际应用:跨平台UI组件、不同数据库的数据访问组件、多主题应用等。
代码示例:跨平台UI组件工厂
// UI组件接口
public interface Button {
void render();
void onClick();
}
public interface TextField {
void render();
void onType();
}
// Windows平台组件实现
public class WindowsButton implements Button {
@Override
public void render() {
System.out.println("渲染Windows风格按钮");
}
@Override
public void onClick() {
System.out.println("Windows按钮点击效果");
}
}
public class WindowsTextField implements TextField {
@Override
public void render() {
System.out.println("渲染Windows风格文本框");
}
@Override
public void onType() {
System.out.println("Windows文本框输入效果");
}
}
// Mac平台组件实现
public class MacButton implements Button {
@Override
public void render() {
System.out.println("渲染Mac风格按钮");
}
@Override
public void onClick() {
System.out.println("Mac按钮点击效果");
}
}
public class MacTextField implements TextField {
@Override
public void render() {
System.out.println("渲染Mac风格文本框");
}
@Override
public void onType() {
System.out.println("Mac文本框输入效果");
}
}
// 抽象工厂接口
public interface GUIFactory {
Button createButton();
TextField createTextField();
}
// 具体工厂实现
public class WindowsFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public TextField createTextField() {
return new WindowsTextField();
}
}
public class MacFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public TextField createTextField() {
return new MacTextField();
}
}
// 客户端代码
public class Application {
private Button button;
private TextField textField;
public Application(GUIFactory factory) {
button = factory.createButton();
textField = factory.createTextField();
}
public void render() {
button.render();
textField.render();
}
public static void main(String[] args) {
// 根据操作系统选择工厂
GUIFactory factory;
String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("windows")) {
factory = new WindowsFactory();
} else {
factory = new MacFactory();
}
Application app = new Application(factory);
app.render();
}
}
优点:
- 保证了一系列相关产品的一致性
- 隔离了具体类的生成,使客户端不需要知道什么被创建
缺点:
- 产品族扩展困难,需要修改抽象工厂的接口
- 增加了系统的抽象性和理解难度
建造者模式
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
实际应用:复杂对象创建、配置对象、API客户端构建等。
代码示例:构建HTTP请求
public class HttpRequest {
private final String url;
private final String method;
private final Map<String, String> headers;
private final Map<String, String> parameters;
private final String body;
private final int timeout;
private HttpRequest(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers;
this.parameters = builder.parameters;
this.body = builder.body;
this.timeout = builder.timeout;
}
// Getters...
public static class Builder {
// 必需参数
private final String url;
private String method = "GET";
// 可选参数
private Map<String, String> headers = new HashMap<>();
private Map<String, String> parameters = new HashMap<>();
private String body = "";
private int timeout = 30000; // 默认30秒
public Builder(String url) {
this.url = url;
}
public Builder method(String method) {
this.method = method;
return this;
}
public Builder addHeader(String name, String value) {
this.headers.put(name, value);
return this;
}
public Builder addParameter(String name, String value) {
this.parameters.put(name, value);
return this;
}
public Builder body(String body) {
this.body = body;
return this;
}
public Builder timeout(int timeout) {
this.timeout = timeout;
return this;
}
public HttpRequest build() {
return new HttpRequest(this);
}
}
}
// 客户端代码
public class HttpClient {
public static void main(String[] args) {
HttpRequest request = new HttpRequest.Builder("https://api.example.com/data")
.method("POST")
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", "Bearer token123")
.addParameter("id", "123")
.body("{\"name\":\"John\",\"age\":30}")
.timeout(5000)
.build();
// 使用request对象发送请求...
}
}
优点:
- 分离复杂对象的构建和表示
- 同样的构建过程可以创建不同的产品
- 可以更精细地控制构建过程
缺点:
- 产品必须有足够的共同点,范围受限
- 构建者模式比较复杂,增加了代码量
原型模式
定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
实际应用:对象复制、对象缓存、避免重复创建对象等。
代码示例:文档对象克隆
// 原型接口
public interface Prototype extends Cloneable {
Prototype clone();
}
// 具体原型:文档类
public class Document implements Prototype {
private String title;
private String content;
private List<String> authors;
private Map<String, String> metadata;
public Document(String title, String content) {
this.title = title;
this.content = content;
this.authors = new ArrayList<>();
this.metadata = new HashMap<>();
}
// 深拷贝实现
@Override
public Document clone() {
try {
Document clone = (Document) super.clone();
// 深拷贝集合类型属性
clone.authors = new ArrayList<>(this.authors);
clone.metadata = new HashMap<>(this.metadata);
return clone;
} catch (CloneNotSupportedException e) {
return null;
}
}
// Getters and Setters...
public void addAuthor(String author) {
authors.add(author);
}
public void addMetadata(String key, String value) {
metadata.put(key, value);
}
@Override
public String toString() {
return "Document{" +
"title='" + title + '\'' +
", content='" + content + '\'' +
", authors=" + authors +
", metadata=" + metadata +
'}';
}
}
// 客户端代码
public class DocumentManager {
private Map<String, Document> documentRegistry = new HashMap<>();
public DocumentManager() {
// 初始化常用文档模板
Document report = new Document("报告模板", "这是一份标准报告模板");
report.addAuthor("系统管理员");
report.addMetadata("type", "report");
report.addMetadata("version", "1.0");
Document letter = new Document("信件模板", "这是一份标准信件模板");
letter.addAuthor("系统管理员");
letter.addMetadata("type", "letter");
// 注册模板
documentRegistry.put("report", report);
documentRegistry.put("letter", letter);
}
public Document createDocument(String type) {
Document template = documentRegistry.get(type);
if (template == null) {
throw new IllegalArgumentException("未知的文档类型: " + type);
}
return template.clone();
}
public static void main(String[] args) {
DocumentManager manager = new DocumentManager();
// 基于报告模板创建新文档
Document myReport = manager.createDocument("report");
myReport.addAuthor("张三");
System.out.println(myReport);
// 基于信件模板创建新文档
Document myLetter = manager.createDocument("letter");
myLetter.addAuthor("李四");
System.out.println(myLetter);
}
}
优点:
- 隐藏了创建对象的复杂性
- 允许在运行时动态添加或删除产品
- 允许复制对象,而不需要知道具体的类
缺点:
- 对象的深拷贝可能很复杂
- 克隆包含循环引用的对象可能会很困难
结构型模式
结构型模式关注如何组合类和对象以形成更大的结构,同时保持这些结构的灵活性和高效性。
适配器模式
定义:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。
实际应用:第三方库集成、旧系统接口适配、不同格式数据转换等。
代码示例:支付系统集成
// 目标接口:我们的系统使用的支付接口
public interface PaymentProcessor {
void processPayment(double amount);
PaymentStatus getPaymentStatus(String paymentId);
}
// 已有的第三方支付系统(不兼容我们的接口)
public class ThirdPartyPaymentService {
public void makePayment(String merchantId, double amount, String currency) {
System.out.println("使用第三方服务处理支付: " + amount + " " + currency);
// 处理支付逻辑...
}
public String checkStatus(String merchantId, String transactionId) {
// 检查支付状态...
return "COMPLETED";
}
}
// 支付状态枚举
public enum PaymentStatus {
PENDING, COMPLETED, FAILED, REFUNDED
}
// 适配器:将ThirdPartyPaymentService适配到PaymentProcessor接口
public class ThirdPartyPaymentAdapter implements PaymentProcessor {
private ThirdPartyPaymentService paymentService;
private String merchantId;
private Map<String, String> paymentTransactions; // 存储支付ID与交易ID的映射
public ThirdPartyPaymentAdapter(String merchantId) {
this.paymentService = new ThirdPartyPaymentService();
this.merchantId = merchantId;
this.paymentTransactions = new HashMap<>();
}
@Override
public void processPayment(double amount) {
paymentService.makePayment(merchantId, amount, "CNY");
String paymentId = UUID.randomUUID().toString();
String transactionId = "TXN" + System.currentTimeMillis();
paymentTransactions.put(paymentId, transactionId);
}
@Override
public PaymentStatus getPaymentStatus(String paymentId) {
String transactionId = paymentTransactions.get(paymentId);
if (transactionId == null) {
return PaymentStatus.FAILED;
}
String status = paymentService.checkStatus(merchantId, transactionId);
switch (status) {
case "COMPLETED":
return PaymentStatus.COMPLETED;
case "PENDING":
return PaymentStatus.PENDING;
case "REFUNDED":
return PaymentStatus.REFUNDED;
default:
return PaymentStatus.FAILED;
}
}
}
// 客户端代码
public class PaymentService {
private PaymentProcessor paymentProcessor;
public PaymentService(PaymentProcessor paymentProcessor) {
this.paymentProcessor = paymentProcessor;
}
public void pay(double amount) {
paymentProcessor.processPayment(amount);
System.out.println("支付处理完成");
}
public static void main(String[] args) {
// 使用适配器将第三方支付服务适配到我们的系统
PaymentProcessor adapter = new ThirdPartyPaymentAdapter("MERCHANT_123");
PaymentService paymentService = new PaymentService(adapter);
paymentService.pay(100.0);
}
}
优点:
- 将接口不兼容的类可以一起工作
- 提高了类的复用性
- 增加了类的透明性
缺点:
- 过多使用适配器会让系统变得混乱
- 可能需要重写一部分原有功能,导致代码冗余
桥接模式
定义:将抽象部分与它的实现部分分离,使它们都可以独立地变化。
实际应用:跨平台应用、多驱动支持、主题和外观分离等。
代码示例:消息通知系统
// 实现部分接口
public interface MessageSender {
void sendMessage(String message, String recipient);
}
// 具体实现:短信发送器
public class SMSMessageSender implements MessageSender {
@Override
public void sendMessage(String message, String recipient) {
System.out.println("通过短信发送到 " + recipient + ": " + message);
// 实际短信发送逻辑...
}
}
// 具体实现:邮件发送器
public class EmailMessageSender implements MessageSender {
@Override
public void sendMessage(String message, String recipient) {
System.out.println("通过邮件发送到 " + recipient + ": " + message);
// 实际邮件发送逻辑...
}
}
// 具体实现:微信发送器
public class WeChatMessageSender implements MessageSender {
@Override
public void sendMessage(String message, String recipient) {
System.out.println("通过微信发送到 " + recipient + ": " + message);
// 实际微信发送逻辑...
}
}
// 抽象部分
public abstract class Notification {
protected MessageSender messageSender;
public Notification(MessageSender messageSender) {
this.messageSender = messageSender;
}
public abstract void notify(String message, String recipient);
}
// 扩展抽象部分:普通通知
public class NormalNotification extends Notification {
public NormalNotification(MessageSender messageSender) {
super(messageSender);
}
@Override
public void notify(String message, String recipient) {
messageSender.sendMessage(message, recipient);
}
}
// 扩展抽象部分:紧急通知
public class UrgentNotification extends Notification {
public UrgentNotification(MessageSender messageSender) {
super(messageSender);
}
@Override
public void notify(String message, String recipient) {
String urgentMessage = "[紧急] " + message;
messageSender.sendMessage(urgentMessage, recipient);
// 可能还会有额外的紧急处理逻辑...
}
}
// 客户端代码
public class NotificationService {
public static void main(String[] args) {
// 创建不同的发送器
MessageSender smsSender = new SMSMessageSender();
MessageSender emailSender = new EmailMessageSender();
MessageSender weChatSender = new WeChatMessageSender();
// 创建不同的通知,并指定发送器
Notification normalSmsNotification = new NormalNotification(smsSender);
Notification urgentEmailNotification = new UrgentNotification(emailSender);
Notification urgentWeChatNotification = new UrgentNotification(weChatSender);
// 发送通知
normalSmsNotification.notify("系统维护通知", "13800138000");
urgentEmailNotification.notify("服务器宕机警报", "admin@example.com");
urgentWeChatNotification.notify("数据库连接异常", "技术支持组");
}
}
优点:
- 分离抽象接口及其实现部分
- 提高可扩展性,可以独立扩展实现和抽象
- 实现细节对客户透明
缺点:
- 增加了系统的理解与设计难度
- 需要正确识别出系统中两个独立变化的维度
组合模式
定义:将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
实际应用:文件系统、组织架构、GUI组件树等。
代码示例:组织架构管理系统
// 组件接口
public interface OrganizationComponent {
String getName();
String getDescription();
void add(OrganizationComponent component);
void remove(OrganizationComponent component);
void display(int depth);
double getSalaryBudget();
}
// 叶子节点:员工
public class Employee implements OrganizationComponent {
private String name;
private String position;
private double salary;
public Employee(String name, String position, double salary) {
this.name = name;
this.position = position;
this.salary = salary;
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return position;
}
@Override
public void add(OrganizationComponent component) {
throw new UnsupportedOperationException("员工不能添加下属");
}
@Override
public void remove(OrganizationComponent component) {
throw new UnsupportedOperationException("员工不能移除下属");
}
@Override
public void display(int depth) {
StringBuilder indent = new StringBuilder();
for (int i = 0; i < depth; i++) {
indent.append(" ");
}
System.out.println(indent + "- " + name + " (" + position + ")");
}
@Override
public double getSalaryBudget() {
return salary;
}
}
// 组合节点:部门
public class Department implements OrganizationComponent {
private String name;
private String description;
private List<OrganizationComponent> components = new ArrayList<>();
public Department(String name, String description) {
this.name = name;
this.description = description;
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return description;
}
@Override
public void add(OrganizationComponent component) {
components.add(component);
}
@Override
public void remove(OrganizationComponent component) {
components.remove(component);
}
@Override
public void display(int depth) {
StringBuilder indent = new StringBuilder();
for (int i = 0; i < depth; i++) {
indent.append(" ");
}
System.out.println(indent + "+ " + name + " (" + description + ")");
// 显示所有子组件
for (OrganizationComponent component : components) {
component.display(depth + 1);
}
}
@Override
public double getSalaryBudget() {
double budget = 0;
for (OrganizationComponent component : components) {
budget += component.getSalaryBudget();
}
return budget;
}
}
// 客户端代码
public class OrganizationStructure {
public static void main(String[] args) {
// 创建公司结构
OrganizationComponent company = new Department("ABC科技有限公司", "一家科技公司");
// 创建部门
OrganizationComponent rdDept = new Department("研发部", "负责产品研发");
OrganizationComponent salesDept = new Department("销售部", "负责产品销售");
// 创建子部门
OrganizationComponent frontEndTeam = new Department("前端组", "负责前端开发");
OrganizationComponent backEndTeam = new Department("后端组", "负责后端开发");
// 创建员工
OrganizationComponent cto = new Employee("张三", "CTO", 30000);
OrganizationComponent salesManager = new Employee("李四", "销售经理", 20000);
OrganizationComponent frontEndLead = new Employee("王五", "前端负责人", 18000);
OrganizationComponent frontEndDev1 = new Employee("赵六", "前端开发", 12000);
OrganizationComponent backEndDev1 = new Employee("钱七", "后端开发", 15000);
OrganizationComponent salesRep1 = new Employee("孙八", "销售代表", 8000);
// 构建组织结构
company.add(cto);
company.add(rdDept);
company.add(salesDept);
rdDept.add(frontEndTeam);
rdDept.add(backEndTeam);
frontEndTeam.add(frontEndLead);
frontEndTeam.add(frontEndDev1);
backEndTeam.add(backEndDev1);
salesDept.add(salesManager);
salesDept.add(salesRep1);
// 显示组织结构
company.display(0);
// 计算各部门薪资预算
System.out.println("\n薪资预算:");
System.out.println("公司总预算: " + company.getSalaryBudget());
System.out.println("研发部预算: " + rdDept.getSalaryBudget());
System.out.println("销售部预算: " + salesDept.getSalaryBudget());
System.out.println("前端组预算: " + frontEndTeam.getSalaryBudget());
}
}
优点:
- 定义了包含基本对象和组合对象的层次结构
- 简化客户端代码,客户端可以一致地使用组合结构或单个对象
- 更容易增加新类型的组件
缺点:
- 使设计变得更加抽象
- 很难对组件类型进行限制
装饰器模式
定义:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式比生成子类更为灵活。
实际应用:I/O流包装、UI组件增强、服务功能扩展等。
代码示例:咖啡订单系统
// 组件接口
public interface Beverage {
String getDescription();
double cost();
}
// 具体组件:基础咖啡类型
public class Espresso implements Beverage {
@Override
public String getDescription() {
return "浓缩咖啡";
}
@Override
public double cost() {
return 20.0;
}
}
public class Americano implements Beverage {
@Override
public String getDescription() {
return "美式咖啡";
}
@Override
public double cost() {
return 25.0;
}
}
// 装饰器基类
public abstract class CondimentDecorator implements Beverage {
protected Beverage beverage;
public CondimentDecorator(Beverage beverage) {
this.beverage = beverage;
}
@Override
public abstract String getDescription();
}
// 具体装饰器:调料
public class Milk extends CondimentDecorator {
public Milk(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + ", 加牛奶";
}
@Override
public double cost() {
return beverage.cost() + 5.0;
}
}
public class Mocha extends CondimentDecorator {
public Mocha(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + ", 加摩卡";
}
@Override
public double cost() {
return beverage.cost() + 8.0;
}
}
public class Whip extends CondimentDecorator {
public Whip(Beverage beverage) {
super(beverage);
}
@Override
public String getDescription() {
return beverage.getDescription() + ", 加奶泡";
}
@Override
public double cost() {
return beverage.cost() + 3.0;
}
}
// 客户端代码
public class CoffeeShop {
public static void main(String[] args) {
// 点一杯浓缩咖啡
Beverage beverage1 = new Espresso();
System.out.println(beverage1.getDescription() + " ¥" + beverage1.cost());
// 点一杯加了双份摩卡和奶泡的美式咖啡
Beverage beverage2 = new Americano();
beverage2 = new Mocha(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription() + " ¥" + beverage2.cost());
// 点一杯加牛奶和摩卡的浓缩咖啡
Beverage beverage3 = new Espresso();
beverage3 = new Milk(beverage3);
beverage3 = new Mocha(beverage3);
System.out.println(beverage3.getDescription() + " ¥" + beverage3.cost());
}
}
优点:
- 比继承更灵活,可以动态地添加或删除职责
- 可以用多个装饰器组合,创建多层次的功能
- 避免了在层次结构高层的类有太多的特征
缺点:
- 会产生很多小对象,增加系统复杂度
- 装饰器模式比继承更难理解和调试
外观模式
定义:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
实际应用:复杂系统的简化接口、第三方库封装、子系统整合等。
代码示例:智能家居控制系统
// 子系统类:灯光控制
public class LightSystem {
public void turnOn() {
System.out.println("灯光已打开");
}
public void turnOff() {
System.out.println("灯光已关闭");
}
public void dim(int level) {
System.out.println("灯光亮度调整为: " + level + "%");
}
}
// 子系统类:空调控制
public class AirConditionerSystem {
public void turnOn() {
System.out.println("空调已打开");
}
public void turnOff() {
System.out.println("空调已关闭");
}
public void setTemperature(int temperature) {
System.out.println("空调温度设置为: " + temperature + "°C");
}
public void setMode(String mode) {
System.out.println("空调模式设置为: " + mode);
}
}
// 子系统类:音响控制
public class MusicSystem {
public void turnOn() {
System.out.println("音响已打开");
}
public void turnOff() {
System.out.println("音响已关闭");
}
public void setVolume(int volume) {
System.out.println("音量设置为: " + volume);
}
public void setChannel(String channel) {
System.out.println("频道切换为: " + channel);
}
}
// 子系统类:窗帘控制
public class CurtainSystem {
public void open() {
System.out.println("窗帘已打开");
}
public void close() {
System.out.println("窗帘已关闭");
}
public void setPosition(int position) {
System.out.println("窗帘位置设置为: " + position + "%");
}
}
// 外观类:智能家居控制中心
public class SmartHomeFacade {
private LightSystem lightSystem;
private AirConditionerSystem airConditionerSystem;
private MusicSystem musicSystem;
private CurtainSystem curtainSystem;
public SmartHomeFacade() {
lightSystem = new LightSystem();
airConditionerSystem = new AirConditionerSystem();
musicSystem = new MusicSystem();
curtainSystem = new CurtainSystem();
}
// 简化的接口:回家模式
public void homeMode() {
System.out.println("激活回家模式...");
curtainSystem.open();
lightSystem.turnOn();
lightSystem.dim(70);
airConditionerSystem.turnOn();
airConditionerSystem.setTemperature(24);
airConditionerSystem.setMode("制冷");
musicSystem.turnOn();
musicSystem.setChannel("轻音乐");
musicSystem.setVolume(30);
}
// 简化的接口:离家模式
public void awayMode() {
System.out.println("激活离家模式...");
curtainSystem.close();
lightSystem.turnOff();
airConditionerSystem.turnOff();
musicSystem.turnOff();
}
// 简化的接口:电影模式
public void movieMode() {
System.out.println("激活电影模式...");
curtainSystem.close();
lightSystem.dim(30);
airConditionerSystem.setTemperature(22);
musicSystem.turnOn();
musicSystem.setChannel("环绕声");
musicSystem.setVolume(60);
}
// 简化的接口:睡眠模式
public void sleepMode() {
System.out.println("激活睡眠模式...");
curtainSystem.close();
lightSystem.turnOff();
airConditionerSystem.setTemperature(26);
airConditionerSystem.setMode("睡眠");
musicSystem.turnOff();
}
}
// 客户端代码
public class SmartHomeClient {
public static void main(String[] args) {
SmartHomeFacade smartHome = new SmartHomeFacade();
System.out.println("=== 回家场景 ===");
smartHome.homeMode();
System.out.println("\n=== 准备看电影 ===");
smartHome.movieMode();
System.out.println("\n=== 准备睡觉 ===");
smartHome.sleepMode();
System.out.println("\n=== 准备出门 ===");
smartHome.awayMode();
}
}
优点:
- 简化了客户端与复杂子系统的交互
- 实现了子系统与客户端的松耦合
- 提供了一个简单的接口,隐藏了系统的复杂性
缺点:
- 外观可能成为与所有子系统耦合的上帝类
- 不符合开闭原则,增加新的子系统需要修改外观类
享元模式
定义:运用共享技术有效地支持大量细粒度的对象,避免创建过多对象导致内存溢出。
实际应用:字符串常量池、数据库连接池、缓存池等。
代码示例:文本编辑器中的字符渲染
// 享元接口
public interface Character {
void display(int fontSize, String fontFamily, int x, int y);
}
// 具体享元类
public class ConcreteCharacter implements Character {
private char symbol; // 内部状态,可以共享
public ConcreteCharacter(char symbol) {
this.symbol = symbol;
// 模拟加载字符资源的耗时操作
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("创建字符: " + symbol);
}
@Override
public void display(int fontSize, String fontFamily, int x, int y) {
// fontSize, fontFamily, x, y 是外部状态,不可共享
System.out.println("显示字符 " + symbol +
" [字体: " + fontFamily +
", 大小: " + fontSize +
", 位置: (" + x + "," + y + ")]");
}
}
// 享元工厂
public class CharacterFactory {
private Map<Character, ConcreteCharacter> characterPool = new HashMap<>();
public Character getCharacter(char symbol) {
// 如果字符已经在池中,则直接返回
if (characterPool.containsKey(symbol)) {
return characterPool.get(symbol);
} else {
// 否则创建一个新的字符对象并添加到池中
ConcreteCharacter character = new ConcreteCharacter(symbol);
characterPool.put(symbol, character);
return character;
}
}
public int getPoolSize() {
return characterPool.size();
}
}
// 客户端代码
public class TextEditor {
public static void main(String[] args) {
CharacterFactory factory = new CharacterFactory();
// 模拟文本编辑器显示文本
String text = "Hello, World! Welcome to Java Design Patterns.";
int x = 0;
int y = 0;
System.out.println("开始渲染文本...");
long startTime = System.currentTimeMillis();
for (char c : text.toCharArray()) {
Character character = factory.getCharacter(c);
// 每个字符的外部状态可能不同
character.display(12, "Arial", x, y);
x += 10; // 移动到下一个位置
if (x > 100) {
x = 0;
y += 20; // 换行
}
}
long endTime = System.currentTimeMillis();
System.out.println("渲染完成,用时: " + (endTime - startTime) + "ms");
System.out.println("字符对象池大小: " + factory.getPoolSize() +
" (文本中不同字符的数量)");
}
}
优点:
- 大大减少了对象的创建,节省内存
- 相同的对象只要保存一份,降低了系统的复杂度
缺点:
- 提高了系统的复杂度,需要分离内部状态和外部状态
- 使得系统逻辑复杂化,增加了程序的复杂性
代理模式
定义:为其他对象提供一种代理以控制对这个对象的访问。
实际应用:远程代理、虚拟代理、保护代理、缓存代理等。
代码示例:图片加载的虚拟代理
// 主题接口
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);
// 模拟图片加载的耗时操作
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void display() {
System.out.println("显示图片: " + filename);
}
}
// 代理:虚拟代理
public class ProxyImage implements Image {
private String filename;
private RealImage realImage;
public ProxyImage(String filename) {
this.filename = filename;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(filename);
}
realImage.display();
}
}
// 客户端代码
public class ImageViewer {
public static void main(String[] args) {
// 使用代理创建图片对象
Image image1 = new ProxyImage("photo1.jpg");
Image image2 = new ProxyImage("photo2.jpg");
// 第一次调用display()时会加载图片
System.out.println("首次显示图片1:");
image1.display();
System.out.println("\n首次显示图片2:");
image2.display();
// 第二次调用display()不会重新加载图片
System.out.println("\n再次显示图片1:");
image1.display();
}
}
优点:
- 可以在不修改目标对象的前提下,控制对目标对象的访问
- 将客户端与目标对象分离,降低系统的耦合度
- 可以扩展目标对象的功能
缺点:
- 增加了系统的复杂度
- 可能会导致请求的处理速度变慢
行为型模式
行为型模式关注对象之间的通信,描述类或对象之间怎样相互协作以及怎样分配职责。
责任链模式
定义:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
实际应用:日志记录、异常处理、请求过滤、权限验证等。
代码示例:企业审批流程
// 请求类
public class PurchaseRequest {
private int id;
private double amount;
private String purpose;
public PurchaseRequest(int id, double amount, String purpose) {
this.id = id;
this.amount = amount;
this.purpose = purpose;
}
public int getId() {
return id;
}
public double getAmount() {
return amount;
}
public String getPurpose() {
return purpose;
}
@Override
public String toString() {
return "采购申请 #" + id + " [金额: " + amount + ", 用途: " + purpose + "]";
}
}
// 处理者接口
public abstract class Approver {
protected Approver nextApprover;
protected String name;
public Approver(String name) {
this.name = name;
}
public void setNextApprover(Approver nextApprover) {
this.nextApprover = nextApprover;
}
public abstract void processRequest(PurchaseRequest request);
}
// 具体处理者:部门经理
public class DepartmentManager extends Approver {
public DepartmentManager(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() <= 5000) {
System.out.println(name + " (部门经理) 已批准 " + request);
} else if (nextApprover != null) {
System.out.println(name + " (部门经理) 无权批准,转交给上级...");
nextApprover.processRequest(request);
} else {
System.out.println("请求无法批准");
}
}
}
// 具体处理者:副总裁
public class VicePresident extends Approver {
public VicePresident(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() <= 25000) {
System.out.println(name + " (副总裁) 已批准 " + request);
} else if (nextApprover != null) {
System.out.println(name + " (副总裁) 无权批准,转交给上级...");
nextApprover.processRequest(request);
} else {
System.out.println("请求无法批准");
}
}
}
// 具体处理者:总裁
public class President extends Approver {
public President(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() <= 100000) {
System.out.println(name + " (总裁) 已批准 " + request);
} else if (nextApprover != null) {
System.out.println(name + " (总裁) 无权批准,转交给上级...");
nextApprover.processRequest(request);
} else {
System.out.println("请求无法批准,需要董事会审批");
}
}
}
// 具体处理者:董事会
public class BoardOfDirectors extends Approver {
public BoardOfDirectors(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() <= 500000) {
System.out.println(name + " (董事会) 已批准 " + request);
} else {
System.out.println("金额过大," + name + " (董事会) 拒绝了 " + request);
}
}
}
// 客户端代码
public class PurchaseSystem {
public static void main(String[] args) {
// 创建责任链
Approver manager = new DepartmentManager("张经理");
Approver vp = new VicePresident("王副总");
Approver president = new President("李总");
Approver board = new BoardOfDirectors("董事会");
// 设置责任链
manager.setNextApprover(vp);
vp.setNextApprover(president);
president.setNextApprover(board);
// 创建采购请求
PurchaseRequest request1 = new PurchaseRequest(1, 4500, "购买办公设备");
PurchaseRequest request2 = new PurchaseRequest(2, 20000, "团队建设活动");
PurchaseRequest request3 = new PurchaseRequest(3, 60000, "服务器升级");
PurchaseRequest request4 = new PurchaseRequest(4, 300000, "部门扩建");
PurchaseRequest request5 = new PurchaseRequest(5, 600000, "公司收购");
// 处理请求
System.out.println("===== 请求1 =====");
manager.processRequest(request1);
System.out.println("\n===== 请求2 =====");
manager.processRequest(request2);
System.out.println("\n===== 请求3 =====");
manager.processRequest(request3);
System.out.println("\n===== 请求4 =====");
manager.processRequest(request4);
System.out.println("\n===== 请求5 =====");
manager.processRequest(request5);
}
}
优点:
- 降低了对象之间的耦合度
- 增强了系统的可扩展性
- 责任分担,每个类只需关注自己的职责
缺点:
- 不能保证请求一定会被处理
- 可能会导致系统性能下降,特别是链条很长的时候
- 调试不方便
命令模式
定义:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
实际应用:GUI按钮点击、事务管理、命令调度、多级撤销等。
代码示例:智能家居遥控器
// 命令接口
public interface Command {
void execute();
void undo();
}
// 接收者:灯
public class Light {
private String location;
public Light(String location) {
this.location = location;
}
public void on() {
System.out.println(location + " 灯已打开");
}
public void off() {
System.out.println(location + " 灯已关闭");
}
}
// 接收者:音响
public class Stereo {
private String location;
public Stereo(String location) {
this.location = location;
}
public void on() {
System.out.println(location + " 音响已打开");
}
public void off() {
System.out.println(location + " 音响已关闭");
}
public void setCD() {
System.out.println(location + " 音响已设置为CD模式");
}
public void setVolume(int volume) {
System.out.println(location + " 音响音量设置为 " + volume);
}
}
// 具体命令:开灯
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.on();
}
@Override
public void undo() {
light.off();
}
}
// 具体命令:关灯
public class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.off();
}
@Override
public void undo() {
light.on();
}
}
// 具体命令:打开音响
public class StereoOnWithCDCommand implements Command {
private Stereo stereo;
public StereoOnWithCDCommand(Stereo stereo) {
this.stereo = stereo;
}
@Override
public void execute() {
stereo.on();
stereo.setCD();
stereo.setVolume(11);
}
@Override
public void undo() {
stereo.off();
}
}
// 具体命令:关闭音响
public class StereoOffCommand implements Command {
private Stereo stereo;
public StereoOffCommand(Stereo stereo) {
this.stereo = stereo;
}
@Override
public void execute() {
stereo.off();
}
@Override
public void undo() {
stereo.on();
stereo.setCD();
stereo.setVolume(11);
}
}
// 空命令(无操作)
public class NoCommand implements Command {
@Override
public void execute() {
// 什么也不做
}
@Override
public void undo() {
// 什么也不做
}
}
// 调用者:遥控器
public class RemoteControl {
private Command[] onCommands;
private Command[] offCommands;
private Command undoCommand;
public RemoteControl() {
onCommands = new Command[7];
offCommands = new Command[7];
Command noCommand = new NoCommand();
for (int i = 0; i < 7; i++) {
onCommands[i] = noCommand;
offCommands[i] = noCommand;
}
undoCommand = noCommand;
}
public void setCommand(int slot, Command onCommand, Command offCommand) {
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
public void onButtonWasPushed(int slot) {
onCommands[slot].execute();
undoCommand = onCommands[slot];
}
public void offButtonWasPushed(int slot) {
offCommands[slot].execute();
undoCommand = offCommands[slot];
}
public void undoButtonWasPushed() {
undoCommand.undo();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("\n------ 遥控器 ------\n");
for (int i = 0; i < onCommands.length; i++) {
sb.append("[插槽 " + i + "] " + onCommands[i].getClass().getSimpleName() + " "
+ offCommands[i].getClass().getSimpleName() + "\n");
}
sb.append("[撤销] " + undoCommand.getClass().getSimpleName() + "\n");
return sb.toString();
}
}
// 客户端代码
public class RemoteControlTest {
public static void main(String[] args) {
// 创建遥控器
RemoteControl remote = new RemoteControl();
// 创建设备
Light livingRoomLight = new Light("客厅");
Light kitchenLight = new Light("厨房");
Stereo stereo = new Stereo("客厅");
// 创建命令
LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight);
LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight);
LightOnCommand kitchenLightOn = new LightOnCommand(kitchenLight);
LightOffCommand kitchenLightOff = new LightOffCommand(kitchenLight);
StereoOnWithCDCommand stereoOn = new StereoOnWithCDCommand(stereo);
StereoOffCommand stereoOff = new StereoOffCommand(stereo);
// 设置命令到遥控器
remote.setCommand(0, livingRoomLightOn, livingRoomLightOff);
remote.setCommand(1, kitchenLightOn, kitchenLightOff);
remote.setCommand(2, stereoOn, stereoOff);
// 显示遥控器
System.out.println(remote);
// 测试按钮
System.out.println("--- 按下按钮 ---");
remote.onButtonWasPushed(0);
remote.offButtonWasPushed(0);
remote.onButtonWasPushed(1);
remote.offButtonWasPushed(1);
remote.onButtonWasPushed(2);
remote.offButtonWasPushed(2);
// 测试撤销
System.out.println("\n--- 测试撤销 ---");
remote.onButtonWasPushed(0);
remote.undoButtonWasPushed();
}
}
优点:
- 将请求发送者和接收者解耦
- 可以将命令对象存储在队列中
- 可以方便地实现撤销和重做功能
- 可以组合命令,实现宏命令
缺点:
- 可能会导致系统中有过多的具体命令类
- 增加了系统的复杂度
解释器模式
定义:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
实际应用:编译器、正则表达式、SQL解析器等。
代码示例:简单的数学表达式解释器
// 抽象表达式
public interface Expression {
int interpret();
}
// 终结符表达式:数字
public class NumberExpression implements Expression {
private int number;
public NumberExpression(int number) {
this.number = number;
}
@Override
public int interpret() {
return number;
}
}
// 非终结符表达式:加法
public class AddExpression implements Expression {
private Expression leftExpression;
private Expression rightExpression;
public AddExpression(Expression leftExpression, Expression rightExpression) {
this.leftExpression = leftExpression;
this.rightExpression = rightExpression;
}
@Override
public int interpret() {
return leftExpression.interpret() + rightExpression.interpret();
}
}
// 非终结符表达式:减法
public class SubtractExpression implements Expression {
private Expression leftExpression;
private Expression rightExpression;
public SubtractExpression(Expression leftExpression, Expression rightExpression) {
this.leftExpression = leftExpression;
this.rightExpression = rightExpression;
}
@Override
public int interpret() {
return leftExpression.interpret() - rightExpression.interpret();
}
}
// 非终结符表达式:乘法
public class MultiplyExpression implements Expression {
private Expression leftExpression;
private Expression rightExpression;
public MultiplyExpression(Expression leftExpression, Expression rightExpression) {
this.leftExpression = leftExpression;
this.rightExpression = rightExpression;
}
@Override
public int interpret() {
return leftExpression.interpret() * rightExpression.interpret();
}
}
// 解析器:将字符串解析为表达式
public class Parser {
public static Expression parse(String expression) {
// 这里简化处理,假设输入格式为"数字 运算符 数字"
String[] tokens = expression.split(" ");
if (tokens.length != 3) {
throw new IllegalArgumentException("Invalid expression format");
}
Expression leftExpression = new NumberExpression(Integer.parseInt(tokens[0]));
Expression rightExpression = new NumberExpression(Integer.parseInt(tokens[2]));
switch (tokens[1]) {
case "+":
return new AddExpression(leftExpression, rightExpression);
case "-":
return new SubtractExpression(leftExpression, rightExpression);
case "*":
return new MultiplyExpression(leftExpression, rightExpression);
default:
throw new IllegalArgumentException("Unknown operator: " + tokens[1]);
}
}
}
// 客户端代码
public class Calculator {
public static void main(String[] args) {
String[] expressions = {"5 + 3", "10 - 4", "7 * 2"};
for (String expressionStr : expressions) {
Expression expression = Parser.parse(expressionStr);
int result = expression.interpret();
System.out.println(expressionStr + " = " + result);
}
}
}
优点:
- 易于改变和扩展文法
- 每一条文法规则都可以表示为一个类,方便维护
- 增加新的解释表达式很容易
缺点:
- 对于复杂的文法,类的数量会急剧增加
- 对于频繁更改的文法,维护困难
- 可能会引起效率问题
迭代器模式
定义:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
实际应用:集合遍历、数据库查询结果遍历、目录遍历等。
代码示例:自定义集合遍历
// 迭代器接口
public interface Iterator<T> {
boolean hasNext();
T next();
}
// 集合接口
public interface Collection<T> {
Iterator<T> createIterator();
void add(T item);
int size();
}
// 具体集合:书架
public class BookShelf implements Collection<Book> {
private List<Book> books;
public BookShelf() {
books = new ArrayList<>();
}
@Override
public Iterator<Book> createIterator() {
return new BookShelfIterator(this);
}
@Override
public void add(Book book) {
books.add(book);
}
@Override
public int size() {
return books.size();
}
public Book getBookAt(int index) {
return books.get(index);
}
}
// 具体迭代器:书架迭代器
public class BookShelfIterator implements Iterator<Book> {
private BookShelf bookShelf;
private int index;
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0;
}
@Override
public boolean hasNext() {
return index < bookShelf.size();
}
@Override
public Book next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
}
// 书类
public class Book {
private String name;
private String author;
public Book(String name, String author) {
this.name = name;
this.author = author;
}
public String getName() {
return name;
}
public String getAuthor() {
return author;
}
@Override
public String toString() {
return "《" + name + "》 作者: " + author;
}
}
// 客户端代码
public class Library {
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf();
// 添加书籍
bookShelf.add(new Book("设计模式", "Erich Gamma等"));
bookShelf.add(new Book("重构", "Martin Fowler"));
bookShelf.add(new Book("代码整洁之道", "Robert C. Martin"));
bookShelf.add(new Book("Java编程思想", "Bruce Eckel"));
// 使用迭代器遍历
System.out.println("=== 图书馆藏书列表 ===");
Iterator<Book> iterator = bookShelf.createIterator();
while (iterator.hasNext()) {
Book book = iterator.next();
System.out.println(book);
}
}
}
优点:
- 支持以不同的方式遍历一个聚合对象
- 迭代器简化了聚合类的接口
- 在同一个聚合上可以有多个遍历
- 增加新的聚合类和迭代器类都很方便
缺点:
- 增加了系统的复杂性
- 对于比较简单的遍历,使用迭代器模式显得小题大做
中介者模式
定义:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
实际应用:GUI组件交互、聊天室、航空管制系统等。
代码示例:聊天室系统
// 中介者接口
public interface ChatMediator {
void sendMessage(String message, User user);
void addUser(User user);
}
// 具体中介者:聊天室
public class ChatRoom implements ChatMediator {
private List<User> users;
public ChatRoom() {
this.users = new ArrayList<>();
}
@Override
public void sendMessage(String message, User sender) {
for (User user : users) {
// 消息不发送给发送者自己
if (user != sender) {
user.receive(message);
}
}
}
@Override
public void addUser(User user) {
users.add(user);
System.out.println(user.getName() + " 加入了聊天室");
}
}
// 抽象同事类:用户
public abstract class User {
protected ChatMediator mediator;
protected String name;
public User(ChatMediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}
public String getName() {
return name;
}
public abstract void send(String message);
public abstract void receive(String message);
}
// 具体同事类:普通用户
public class NormalUser extends User {
public NormalUser(ChatMediator mediator, String name) {
super(mediator, name);
}
@Override
public void send(String message) {
System.out.println(name + " 发送消息: " + message);
mediator.sendMessage(message, this);
}
@Override
public void receive(String message) {
System.out.println(name + " 收到消息: " + message);
}
}
// 具体同事类:高级用户
public class PremiumUser extends User {
public PremiumUser(ChatMediator mediator, String name) {
super(mediator, name);
}
@Override
public void send(String message) {
System.out.println("[高级用户] " + name + " 发送消息: " + message);
mediator.sendMessage("[高级用户] " + message, this);
}
@Override
public void receive(String message) {
System.out.println("[高级用户] " + name + " 收到消息: " + message);
}
}
// 客户端代码
public class ChatApplication {
public static void main(String[] args) {
// 创建中介者
ChatMediator chatRoom = new ChatRoom();
// 创建用户
User user1 = new NormalUser(chatRoom, "张三");
User user2 = new NormalUser(chatRoom, "李四");
User user3 = new PremiumUser(chatRoom, "王五");
User user4 = new NormalUser(chatRoom, "赵六");
// 添加用户到聊天室
chatRoom.addUser(user1);
chatRoom.addUser(user2);
chatRoom.addUser(user3);
chatRoom.addUser(user4);
// 用户发送消息
user1.send("大家好!");
System.out.println();
user3.send("你好,我是王五");
System.out.println();
user2.send("今天天气真好");
}
}
优点:
- 降低了对象之间的耦合性,使得对象易于独立地复用
- 将对象间的一对多关联转变为一对一的关联
- 符合迪米特法则
缺点:
- 中介者可能会变得过于复杂
- 可能会导致系统的可维护性变差
备忘录模式
定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。
实际应用:撤销功能、存档功能、事务回滚等。
代码示例:文本编辑器的撤销功能
// 备忘录类
public class TextMemento {
private String text;
private int cursorPosition;
private long timestamp;
public TextMemento(String text, int cursorPosition) {
this.text = text;
this.cursorPosition = cursorPosition;
this.timestamp = System.currentTimeMillis();
}
public String getText() {
return text;
}
public int getCursorPosition() {
return cursorPosition;
}
public long getTimestamp() {
return timestamp;
}
@Override
public String toString() {
return "备忘点 [" + new Date(timestamp) + "] - 文本长度: " + text.length() +
", 光标位置: " + cursorPosition;
}
}
// 发起人:文本编辑器
public class TextEditor {
private String text;
private int cursorPosition;
public TextEditor() {
this.text = "";
this.cursorPosition = 0;
}
public void write(String text) {
String beforeCursor = this.text.substring(0, cursorPosition);
String afterCursor = this.text.substring(cursorPosition);
this.text = beforeCursor + text + afterCursor;
this.cursorPosition += text.length();
System.out.println("写入文本: " + text);
}
public void delete(int length) {
if (cursorPosition - length < 0) {
length = cursorPosition;
}
if (length > 0) {
String beforeCursor = this.text.substring(0, cursorPosition - length);
String afterCursor = this.text.substring(cursorPosition);
String deletedText = this.text.substring(cursorPosition - length, cursorPosition);
this.text = beforeCursor + afterCursor;
this.cursorPosition -= length;
System.out.println("删除文本: " + deletedText);
}
}
public void moveCursor(int position) {
if (position >= 0 && position <= text.length()) {
this.cursorPosition = position;
System.out.println("移动光标到位置: " + position);
}
}
public TextMemento save() {
return new TextMemento(text, cursorPosition);
}
public void restore(TextMemento memento) {
this.text = memento.getText();
this.cursorPosition = memento.getCursorPosition();
System.out.println("恢复到之前的状态");
}
public void display() {
System.out.println("当前文本: \"" + text + "\"");
System.out.println("光标位置: " + cursorPosition);
}
}
// 管理者:历史记录
public class History {
private List<TextMemento> mementos = new ArrayList<>();
private int currentIndex = -1;
public void push(TextMemento memento) {
// 如果在历史中间进行了新操作,则清除后面的历史
if (currentIndex < mementos.size() - 1) {
mementos = mementos.subList(0, currentIndex + 1);
}
mementos.add(memento);
currentIndex = mementos.size() - 1;
System.out.println("保存当前状态");
}
public TextMemento undo() {
if (currentIndex <= 0) {
System.out.println("已经是最早的状态,无法撤销");
return mementos.get(0);
}
currentIndex--;
TextMemento memento = mementos.get(currentIndex);
System.out.println("撤销到: " + memento);
return memento;
}
public TextMemento redo() {
if (currentIndex >= mementos.size() - 1) {
System.out.println("已经是最新的状态,无法重做");
return mementos.get(currentIndex);
}
currentIndex++;
TextMemento memento = mementos.get(currentIndex);
System.out.println("重做到: " + memento);
return memento;
}
public void showHistory() {
System.out.println("=== 历史记录 ===");
for (int i = 0; i < mementos.size(); i++) {
String marker = (i == currentIndex) ? " <- 当前" : "";
System.out.println(i + ": " + mementos.get(i) + marker);
}
}
}
// 客户端代码
public class TextEditorApp {
public static void main(String[] args) {
TextEditor editor = new TextEditor();
History history = new History();
// 初始状态
history.push(editor.save());
// 编辑操作
editor.write("Hello");
editor.display();
history.push(editor.save());
editor.write(" World");
editor.display();
history.push(editor.save());
editor.write("!");
editor.display();
history.push(editor.save());
editor.moveCursor(5);
editor.write(" Beautiful");
editor.display();
history.push(editor.save());
// 显示历史记录
history.showHistory();
// 撤销操作
System.out.println("\n=== 执行撤销 ===");
editor.restore(history.undo());
editor.display();
System.out.println("\n=== 再次执行撤销 ===");
editor.restore(history.undo());
editor.display();
// 重做操作
System.out.println("\n=== 执行重做 ===");
editor.restore(history.redo());
editor.display();
// 在历史中间进行新操作
System.out.println("\n=== 在历史中间进行新操作 ===");
editor.delete(6);
editor.display();
history.push(editor.save());
// 再次显示历史记录
history.showHistory();
}
}
优点:
- 提供了一种状态恢复的机制
- 实现了信息的封装,客户端不需要关心状态的保存细节
- 提供了可以回到过去某一状态的机制
缺点:
- 如果状态数据较大,或者频繁保存状态,会占用大量内存
- 可能需要额外的存储空间和管理机制
观察者模式
定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
实际应用:事件处理系统、消息订阅、数据同步等。
代码示例:股票价格监控系统
// 主题接口
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 观察者接口
public interface Observer {
void update(String stockName, double price);
}
// 具体主题:股票
public class Stock implements Subject {
private String name;
private double price;
private List<Observer> observers;
public Stock(String name, double price) {
this.name = name;
this.price = price;
this.observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer observer) {
if (!observers.contains(observer)) {
observers.add(observer);
}
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(name, price);
}
}
public void setPrice(double price) {
System.out.println("\n" + name + " 股票价格更新: " + this.price + " -> " + price);
this.price = price;
notifyObservers();
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
}
// 具体观察者:投资者
public class Investor implements Observer {
private String name;
private Map<String, Double> stocks;
public Investor(String name) {
this.name = name;
this.stocks = new HashMap<>();
}
@Override
public void update(String stockName, double price) {
System.out.println(name + " 收到 " + stockName + " 价格更新: " + price);
// 记录关注的股票价格
stocks.put(stockName, price);
// 根据价格变化做出决策
makeDecision(stockName, price);
}
private void makeDecision(String stockName, double price) {
// 简单的决策逻辑
if (price > 100) {
System.out.println(name + " 决定卖出 " + stockName);
} else if (price < 50) {
System.out.println(name + " 决定买入 " + stockName);
} else {
System.out.println(name + " 决定持有 " + stockName);
}
}
public void addInterestedStock(Stock stock) {
stock.registerObserver(this);
stocks.put(stock.getName(), stock.getPrice());
System.out.println(name + " 开始关注股票 " + stock.getName() +
",当前价格: " + stock.getPrice());
}
public void removeInterestedStock(Stock stock) {
stock.removeObserver(this);
stocks.remove(stock.getName());
System.out.println(name + " 不再关注股票 " + stock.getName());
}
}
// 具体观察者:股票分析师
public class StockAnalyst implements Observer {
private String name;
private Map<String, List<Double>> stockHistory;
public StockAnalyst(String name) {
this.name = name;
this.stockHistory = new HashMap<>();
}
@Override
public void update(String stockName, double price) {
System.out.println("分析师 " + name + " 收到 " + stockName + " 价格更新: " + price);
// 记录股票价格历史
stockHistory.putIfAbsent(stockName, new ArrayList<>());
stockHistory.get(stockName).add(price);
// 分析股票趋势
analyzeTrend(stockName);
}
private void analyzeTrend(String stockName) {
List<Double> history = stockHistory.get(stockName);
if (history.size() < 2) {
System.out.println("分析师 " + name + ": " + stockName + " 数据不足,无法分析趋势");
return;
}
double current = history.get(history.size() - 1);
double previous = history.get(history.size() - 2);
if (current > previous) {
System.out.println("分析师 " + name + ": " + stockName + " 呈上升趋势,预计将继续上涨");
} else if (current < previous) {
System.out.println("分析师 " + name + ": " + stockName + " 呈下降趋势,预计将继续下跌");
} else {
System.out.println("分析师 " + name + ": " + stockName + " 价格稳定,预计将维持当前价位");
}
}
public void addInterestedStock(Stock stock) {
stock.registerObserver(this);
stockHistory.putIfAbsent(stock.getName(), new ArrayList<>());
stockHistory.get(stock.getName()).add(stock.getPrice());
System.out.println("分析师 " + name + " 开始关注股票 " + stock.getName());
}
}
// 客户端代码
public class StockMarket {
public static void main(String[] args) {
// 创建股票
Stock appleStock = new Stock("苹果", 150.0);
Stock googleStock = new Stock("谷歌", 2800.0);
Stock amazonStock = new Stock("亚马逊", 3300.0);
// 创建观察者
Investor investor1 = new Investor("张三");
Investor investor2 = new Investor("李四");
StockAnalyst analyst = new StockAnalyst("王五");
// 投资者关注股票
investor1.addInterestedStock(appleStock);
investor1.addInterestedStock(googleStock);
investor2.addInterestedStock(appleStock);
investor2.addInterestedStock(amazonStock);
// 分析师关注股票
analyst.addInterestedStock(appleStock);
analyst.addInterestedStock(googleStock);
analyst.addInterestedStock(amazonStock);
// 股票价格变化
appleStock.setPrice(145.0);
googleStock.setPrice(2850.0);
// 投资者不再关注某只股票
investor1.removeInterestedStock(googleStock);
// 股票价格继续变化
amazonStock.setPrice(3250.0);
appleStock.setPrice(160.0);
}
}
优点:
- 实现了观察者和被观察者的解耦
- 支持广播通信
- 符合开闭原则,增加新的观察者无需修改原有代码
缺点:
- 如果观察者太多,通知所有观察者会花费较多时间
- 如果观察者和被观察者之间有循环依赖,可能导致系统崩溃
- 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的
状态模式
定义:允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
实际应用:工作流系统、游戏角色状态、订单处理流程等。
代码示例:自动售货机状态管理
// 状态接口
public interface State {
void insertCoin();
void ejectCoin();
void selectProduct();
void dispense();
}
// 具体状态:没有硬币
public class NoCoinState implements State {
private VendingMachine vendingMachine;
public NoCoinState(VendingMachine vendingMachine) {
this.vendingMachine = vendingMachine;
}
@Override
public void insertCoin() {
System.out.println("投入硬币成功");
vendingMachine.setState(vendingMachine.getHasCoinState());
}
@Override
public void ejectCoin() {
System.out.println("没有硬币,无法退币");
}
@Override
public void selectProduct() {
System.out.println("请先投入硬币");
}
@Override
public void dispense() {
System.out.println("请先投入硬币并选择商品");
}
@Override
public String toString() {
return "等待投币";
}
}
// 具体状态:有硬币
public class HasCoinState implements State {
private VendingMachine vendingMachine;
public HasCoinState(VendingMachine vendingMachine) {
this.vendingMachine = vendingMachine;
}
@Override
public void insertCoin() {
System.out.println("已经有硬币了,无需再投");
}
@Override
public void ejectCoin() {
System.out.println("退币成功");
vendingMachine.setState(vendingMachine.getNoCoinState());
}
@Override
public void selectProduct() {
System.out.println("已选择商品");
vendingMachine.setState(vendingMachine.getSoldState());
}
@Override
public void dispense() {
System.out.println("请先选择商品");
}
@Override
public String toString() {
return "等待选择商品";
}
}
// 具体状态:售出商品
public class SoldState implements State {
private VendingMachine vendingMachine;
public SoldState(VendingMachine vendingMachine) {
this.vendingMachine = vendingMachine;
}
@Override
public void insertCoin() {
System.out.println("请等待,正在出货");
}
@Override
public void ejectCoin() {
System.out.println("已选择商品,无法退币");
}
@Override
public void selectProduct() {
System.out.println("已选择商品,请等待出货");
}
@Override
public void dispense() {
System.out.println("商品已出货,请取走");
vendingMachine.releaseProduct();
if (vendingMachine.getCount() > 0) {
vendingMachine.setState(vendingMachine.getNoCoinState());
} else {
System.out.println("商品已售罄");
vendingMachine.setState(vendingMachine.getSoldOutState());
}
}
@Override
public String toString() {
return "正在出货";
}
}
// 具体状态:售罄
public class SoldOutState implements State {
private VendingMachine vendingMachine;
public SoldOutState(VendingMachine vendingMachine) {
this.vendingMachine = vendingMachine;
}
@Override
public void insertCoin() {
System.out.println("商品已售罄,不接受投币");
ejectCoin();
}
@Override
public void ejectCoin() {
System.out.println("没有硬币,无法退币");
}
@Override
public void selectProduct() {
System.out.println("商品已售罄,无法选择");
}
@Override
public void dispense() {
System.out.println("商品已售罄,无法出货");
}
@Override
public String toString() {
return "商品售罄";
}
}
// 上下文:自动售货机
public class VendingMachine {
private State noCoinState;
private State hasCoinState;
private State soldState;
private State soldOutState;
private State currentState;
private int count;
public VendingMachine(int count) {
// 初始化状态
noCoinState = new NoCoinState(this);
hasCoinState = new HasCoinState(this);
soldState = new SoldState(this);
soldOutState = new SoldOutState(this);
this.count = count;
if (count > 0) {
currentState = noCoinState;
} else {
currentState = soldOutState;
}
}
public void insertCoin() {
currentState.insertCoin();
}
public void ejectCoin() {
currentState.ejectCoin();
}
public void selectProduct() {
currentState.selectProduct();
currentState.dispense();
}
public void releaseProduct() {
if (count > 0) {
count--;
System.out.println("商品已发放");
}
}
public void refill(int count) {
this.count += count;
System.out.println("补充商品 " + count + " 个,当前库存: " + this.count);
if (this.count > 0) {
currentState = noCoinState;
}
}
public void setState(State state) {
this.currentState = state;
System.out.println("售货机状态变为: " + state);
}
public int getCount() {
return count;
}
// Getters for states
public State getNoCoinState() {
return noCoinState;
}
public State getHasCoinState() {
return hasCoinState;
}
public State getSoldState() {
return soldState;
}
public State getSoldOutState() {
return soldOutState;
}
}
// 客户端代码
public class VendingMachineTest {
public static void main(String[] args) {
// 创建售货机,初始有5个商品
VendingMachine vendingMachine = new VendingMachine(5);
// 测试正常购买流程
System.out.println("===== 测试正常购买流程 =====");
vendingMachine.insertCoin();
vendingMachine.selectProduct();
// 测试没有投币就选择商品
System.out.println("\n===== 测试没有投币就选择商品 =====");
vendingMachine.selectProduct();
// 测试投币后退币
System.out.println("\n===== 测试投币后退币 =====");
vendingMachine.insertCoin();
vendingMachine.ejectCoin();
// 测试多次投币
System.out.println("\n===== 测试多次投币 =====");
vendingMachine.insertCoin();
vendingMachine.insertCoin();
vendingMachine.selectProduct();
// 测试售罄情况
System.out.println("\n===== 测试售罄情况 =====");
// 购买剩余的商品
for (int i = 0; i < 3; i++) {
vendingMachine.insertCoin();
vendingMachine.selectProduct();
}
// 尝试在售罄状态下购买
vendingMachine.insertCoin();
vendingMachine.selectProduct();
// 补充商品
System.out.println("\n===== 补充商品 =====");
vendingMachine.refill(3);
vendingMachine.insertCoin();
vendingMachine.selectProduct();
}
}
优点:
- 将状态转换显式化,减少了if-else语句
- 状态对象可以被共享
- 容易增加新的状态和转换
缺点:
- 状态模式的使用必然会增加系统类和对象的个数
- 状态模式的结构与实现都较为复杂
策略模式
定义:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。策略模式使得算法可独立于使用它的客户而变化。
实际应用:支付方式选择、排序算法选择、压缩算法选择等。
代码示例:支付系统
// 策略接口
public interface PaymentStrategy {
void pay(double amount);
}
// 具体策略:信用卡支付
public class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
private String name;
private String cvv;
private String expiryDate;
public CreditCardPayment(String cardNumber, String name, String cvv, String expiryDate) {
this.cardNumber = cardNumber;
this.name = name;
this.cvv = cvv;
this.expiryDate = expiryDate;
}
@Override
public void pay(double amount) {
System.out.println("使用信用卡支付 " + amount + " 元");
System.out.println("信用卡信息: " + name + ", " +
"卡号: " + maskCardNumber(cardNumber));
}
private String maskCardNumber(String cardNumber) {
return "xxxx-xxxx-xxxx-" + cardNumber.substring(cardNumber.length() - 4);
}
}
// 具体策略:支付宝支付
public class AlipayPayment implements PaymentStrategy {
private String email;
private String password;
public AlipayPayment(String email, String password) {
this.email = email;
this.password = password;
}
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付 " + amount + " 元");
System.out.println("支付宝账号: " + email);
}
}
// 具体策略:微信支付
public class WeChatPayment implements PaymentStrategy {
private String id;
private String qrCode;
public WeChatPayment(String id, String qrCode) {
this.id = id;
this.qrCode = qrCode;
}
@Override
public void pay(double amount) {
System.out.println("使用微信支付 " + amount + " 元");
System.out.println("微信ID: " + id);
System.out.println("扫描二维码: " + qrCode);
}
}
// 上下文:购物车
public class ShoppingCart {
private List<Item> items;
public ShoppingCart() {
this.items = new ArrayList<>();
}
public void addItem(Item item) {
items.add(item);
}
public void removeItem(Item item) {
items.remove(item);
}
public double calculateTotal() {
return items.stream().mapToDouble(Item::getPrice).sum();
}
public void pay(PaymentStrategy paymentStrategy) {
double amount = calculateTotal();
paymentStrategy.pay(amount);
}
}
// 商品类
public class Item {
private String id;
private String name;
private double price;
public Item(String id, String name, double price) {
this.id = id;
this.name = name;
this.price = price;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
}
// 客户端代码
public class ShoppingCartDemo {
public static void main(String[] args) {
// 创建购物车并添加商品
ShoppingCart cart = new ShoppingCart();
cart.addItem(new Item("1", "手机", 5999));
cart.addItem(new Item("2", "耳机", 999));
cart.addItem(new Item("3", "保护壳", 99));
// 显示总金额
System.out.println("购物车总金额: " + cart.calculateTotal() + " 元");
// 使用不同的支付策略
System.out.println("\n===== 使用信用卡支付 =====");
cart.pay(new CreditCardPayment("1234567890123456", "张三", "123", "12/25"));
System.out.println("\n===== 使用支付宝支付 =====");
cart.pay(new AlipayPayment("zhangsan@example.com", "password"));
System.out.println("\n===== 使用微信支付 =====");
cart.pay(new WeChatPayment("zhangsan", "https://weixin.qq.com/pay/qrcode123456"));
}
}
优点:
- 算法可以自由切换
- 避免使用多重条件判断
- 扩展性良好,增加新的策略很方便
缺点:
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类
- 策略模式将造成产生很多策略类
模板方法模式
定义:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
实际应用:数据导入导出流程、构建流程、测试框架等。
代码示例:数据挖掘应用
// 抽象类,定义算法骨架
public abstract class DataMiner {
// 模板方法,定义算法骨架
public final void mineData(String filePath) {
String rawData = readData(filePath);
String processedData = processData(rawData);
String analysis = analyzeData(processedData);
sendReport(analysis);
// 钩子方法,可选的额外处理
if (shouldStoreData()) {
storeData(processedData);
}
}
// 原始方法 - 由子类实现
protected abstract String readData(String filePath);
// 原始方法 - 由子类实现
protected abstract String processData(String data);
// 具体方法 - 所有子类共享的实现
protected String analyzeData(String data) {
System.out.println("分析数据...");
// 通用的数据分析逻辑
return "数据分析结果:" + data.substring(0, Math.min(20, data.length())) + "...";
}
// 具体方法 - 所有子类共享的实现
protected void sendReport(String analysis) {
System.out.println("发送数据分析报告...");
System.out.println(analysis);
}
// 钩子方法 - 默认实现,子类可以覆盖
protected boolean shouldStoreData() {
return true;
}
// 具体方法 - 所有子类共享的实现
protected void storeData(String data) {
System.out.println("存储处理后的数据到数据库...");
}
}
// 具体子类 - CSV文件数据挖掘器
public class CSVDataMiner extends DataMiner {
@Override
protected String readData(String filePath) {
System.out.println("从CSV文件读取数据: " + filePath);
// 实际应用中,这里会有真正的CSV文件读取逻辑
return "id,name,value\n1,A,100\n2,B,200\n3,C,300";
}
@Override
protected String processData(String data) {
System.out.println("处理CSV数据...");
// 处理CSV特有的数据格式
String[] lines = data.split("\n");
StringBuilder processed = new StringBuilder();
for (int i = 1; i < lines.length; i++) { // 跳过标题行
String[] values = lines[i].split(",");
processed.append("行 ").append(i).append(": ");
processed.append("ID=").append(values[0]).append(", ");
processed.append("名称=").append(values[1]).append(", ");
processed.append("值=").append(values[2]).append("\n");
}
return processed.toString();
}
}
// 具体子类 - JSON文件数据挖掘器
public class JSONDataMiner extends DataMiner {
@Override
protected String readData(String filePath) {
System.out.println("从JSON文件读取数据: " + filePath);
// 实际应用中,这里会有真正的JSON文件读取逻辑
return "[{\"id\":1,\"name\":\"A\",\"value\":100},{\"id\":2,\"name\":\"B\",\"value\":200},{\"id\":3,\"name\":\"C\",\"value\":300}]";
}
@Override
protected String processData(String data) {
System.out.println("处理JSON数据...");
// 处理JSON特有的数据格式
// 实际应用中,这里会使用JSON解析库
String simplified = data.replace("[", "").replace("]", "");
String[] objects = simplified.split("\\},\\{");
StringBuilder processed = new StringBuilder();
for (int i = 0; i < objects.length; i++) {
String obj = objects[i].replace("{", "").replace("}", "");
processed.append("对象 ").append(i + 1).append(": ");
String[] properties = obj.split(",");
for (String property : properties) {
String[] keyValue = property.split(":");
String key = keyValue[0].replace("\"", "");
String value = keyValue[1].replace("\"", "");
processed.append(key).append("=").append(value).append(", ");
}
processed.append("\n");
}
return processed.toString();
}
@Override
protected boolean shouldStoreData() {
// 覆盖钩子方法,决定不存储JSON数据
return false;
}
}
// 具体子类 - 数据库数据挖掘器
public class DatabaseDataMiner extends DataMiner {
@Override
protected String readData(String connectionString) {
System.out.println("从数据库读取数据: " + connectionString);
// 实际应用中,这里会有真正的数据库查询逻辑
return "ID\tNAME\tVALUE\n1\tA\t100\n2\tB\t200\n3\tC\t300";
}
@Override
protected String processData(String data) {
System.out.println("处理数据库数据...");
// 处理数据库特有的数据格式
String[] lines = data.split("\n");
StringBuilder processed = new StringBuilder();
for (int i = 1; i < lines.length; i++) { // 跳过标题行
String[] values = lines[i].split("\t");
processed.append("记录 ").append(i).append(": ");
processed.append("ID=").append(values[0]).append(", ");
processed.append("名称=").append(values[1]).append(", ");
processed.append("值=").append(values[2]).append("\n");
}
return processed.toString();
}
@Override
protected String analyzeData(String data) {
// 覆盖父类的方法,提供特殊的数据库数据分析
System.out.println("使用特殊算法分析数据库数据...");
return "数据库数据分析结果:" + data.substring(0, Math.min(30, data.length())) + "...";
}
}
// 客户端代码
public class DataMiningApp {
public static void main(String[] args) {
System.out.println("===== 使用CSV数据挖掘器 =====");
DataMiner csvMiner = new CSVDataMiner();
csvMiner.mineData("data.csv");
System.out.println("\n===== 使用JSON数据挖掘器 =====");
DataMiner jsonMiner = new JSONDataMiner();
jsonMiner.mineData("data.json");
System.out.println("\n===== 使用数据库数据挖掘器 =====");
DataMiner dbMiner = new DatabaseDataMiner();
dbMiner.mineData("jdbc:mysql://localhost:3306/testdb");
}
}
优点:
- 封装不变部分,扩展可变部分
- 提取公共代码,便于维护
- 行为由父类控制,子类实现
缺点:
- 每一个不同的实现都需要一个子类,导致类的个数增加
- 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构
访问者模式
定义:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
实际应用:文档对象模型(DOM)、编译器设计、复杂对象结构的操作等。
代码示例:公司员工薪资报表系统
// 访问者接口
public interface Visitor {
void visit(Manager manager);
void visit(Developer developer);
void visit(Designer designer);
}
// 元素接口
public interface Employee {
void accept(Visitor visitor);
String getName();
double getSalary();
int getWorkingDays();
}
// 具体元素:经理
public class Manager implements Employee {
private String name;
private double salary;
private int workingDays;
private int teamSize;
public Manager(String name, double salary, int workingDays, int teamSize) {
this.name = name;
this.salary = salary;
this.workingDays = workingDays;
this.teamSize = teamSize;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String getName() {
return name;
}
@Override
public double getSalary() {
return salary;
}
@Override
public int getWorkingDays() {
return workingDays;
}
public int getTeamSize() {
return teamSize;
}
}
// 具体元素:开发人员
public class Developer implements Employee {
private String name;
private double salary;
private int workingDays;
private String programmingLanguage;
public Developer(String name, double salary, int workingDays, String programmingLanguage) {
this.name = name;
this.salary = salary;
this.workingDays = workingDays;
this.programmingLanguage = programmingLanguage;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String getName() {
return name;
}
@Override
public double getSalary() {
return salary;
}
@Override
public int getWorkingDays() {
return workingDays;
}
public String getProgrammingLanguage() {
return programmingLanguage;
}
}
// 具体元素:设计师
public class Designer implements Employee {
private String name;
private double salary;
private int workingDays;
private String designTool;
public Designer(String name, double salary, int workingDays, String designTool) {
this.name = name;
this.salary = salary;
this.workingDays = workingDays;
this.designTool = designTool;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
@Override
public String getName() {
return name;
}
@Override
public double getSalary() {
return salary;
}
@Override
public int getWorkingDays() {
return workingDays;
}
public String getDesignTool() {
return designTool;
}
}
// 具体访问者:薪资报表生成器
public class SalaryReportVisitor implements Visitor {
private double totalSalary = 0;
private Map<String, Double> departmentSalaries = new HashMap<>();
@Override
public void visit(Manager manager) {
double salary = manager.getSalary();
// 经理有管理团队的额外奖金
double bonus = 1000 * manager.getTeamSize();
double totalSalary = salary + bonus;
System.out.println("经理 " + manager.getName() + " 的薪资: " + salary +
" + 团队奖金: " + bonus + " = " + totalSalary);
this.totalSalary += totalSalary;
departmentSalaries.put("管理部门", departmentSalaries.getOrDefault("管理部门", 0.0) + totalSalary);
}
@Override
public void visit(Developer developer) {
double salary = developer.getSalary();
// 开发人员有技术奖金
double bonus = 0;
String language = developer.getProgrammingLanguage();
if ("Java".equalsIgnoreCase(language)) {
bonus = 1000;
} else if ("Python".equalsIgnoreCase(language)) {
bonus = 800;
} else if ("C++".equalsIgnoreCase(language)) {
bonus = 1200;
}
double totalSalary = salary + bonus;
System.out.println("开发人员 " + developer.getName() + " 的薪资: " + salary +
" + " + language + " 技术奖金: " + bonus + " = " + totalSalary);
this.totalSalary += totalSalary;
departmentSalaries.put("开发部门", departmentSalaries.getOrDefault("开发部门", 0.0) + totalSalary);
}
@Override
public void visit(Designer designer) {
double salary = designer.getSalary();
// 设计师有创意奖金
double bonus = 0;
String tool = designer.getDesignTool();
if ("Photoshop".equalsIgnoreCase(tool)) {
bonus = 800;
} else if ("Sketch".equalsIgnoreCase(tool)) {
bonus = 1000;
} else if ("Figma".equalsIgnoreCase(tool)) {
bonus = 900;
}
double totalSalary = salary + bonus;
System.out.println("设计师 " + designer.getName() + " 的薪资: " + salary +
" + " + tool + " 创意奖金: " + bonus + " = " + totalSalary);
this.totalSalary += totalSalary;
departmentSalaries.put("设计部门", departmentSalaries.getOrDefault("设计部门", 0.0) + totalSalary);
}
public void printReport() {
System.out.println("\n===== 薪资报表摘要 =====");
System.out.println("总薪资支出: " + totalSalary);
System.out.println("\n各部门薪资:");
for (Map.Entry<String, Double> entry : departmentSalaries.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
}
// 具体访问者:考勤报表生成器
public class AttendanceReportVisitor implements Visitor {
private int totalWorkingDays = 0;
private int totalEmployees = 0;
private Map<String, Integer> departmentAttendance = new HashMap<>();
private Map<String, Integer> departmentEmployees = new HashMap<>();
@Override
public void visit(Manager manager) {
int workingDays = manager.getWorkingDays();
System.out.println("经理 " + manager.getName() + " 的工作天数: " + workingDays);
totalWorkingDays += workingDays;
totalEmployees++;
departmentAttendance.put("管理部门", departmentAttendance.getOrDefault("管理部门", 0) + workingDays);
departmentEmployees.put("管理部门", departmentEmployees.getOrDefault("管理部门", 0) + 1);
}
@Override
public void visit(Developer developer) {
int workingDays = developer.getWorkingDays();
System.out.println("开发人员 " + developer.getName() + " 的工作天数: " + workingDays);
totalWorkingDays += workingDays;
totalEmployees++;
departmentAttendance.put("开发部门", departmentAttendance.getOrDefault("开发部门", 0) + workingDays);
departmentEmployees.put("开发部门", departmentEmployees.getOrDefault("开发部门", 0) + 1);
}
@Override
public void visit(Designer designer) {
int workingDays = designer.getWorkingDays();
System.out.println("设计师 " + designer.getName() + " 的工作天数: " + workingDays);
totalWorkingDays += workingDays;
totalEmployees++;
departmentAttendance.put("设计部门", departmentAttendance.getOrDefault("设计部门", 0) + workingDays);
departmentEmployees.put("设计部门", departmentEmployees.getOrDefault("设计部门", 0) + 1);
}
public void printReport() {
System.out.println("\n===== 考勤报表摘要 =====");
System.out.println("员工总数: " + totalEmployees);
System.out.println("总工作天数: " + totalWorkingDays);
System.out.println("平均出勤率: " + (totalWorkingDays / (totalEmployees * 22.0) * 100) + "%");
System.out.println("\n各部门考勤:");
for (String department : departmentAttendance.keySet()) {
int attendance = departmentAttendance.get(department);
int employees = departmentEmployees.get(department);
double rate = attendance / (employees * 22.0) * 100;
System.out.println(department + ": " + attendance + " 天 / " +
employees + " 人 = " + rate + "% 出勤率");
}
}
}
// 对象结构
public class Company {
private List<Employee> employees = new ArrayList<>();
public void addEmployee(Employee employee) {
employees.add(employee);
}
public void removeEmployee(Employee employee) {
employees.remove(employee);
}
public void accept(Visitor visitor) {
for (Employee employee : employees) {
employee.accept(visitor);
}
}
}
// 客户端代码
public class CompanyReportSystem {
public static void main(String[] args) {
// 创建公司结构
Company company = new Company();
// 添加员工
company.addEmployee(new Manager("张三", 20000, 20, 5));
company.addEmployee(new Manager("李四", 25000, 22, 3));
company.addEmployee(new Developer("王五", 15000, 21, "Java"));
company.addEmployee(new Developer("赵六", 16000, 18, "Python"));
company.addEmployee(new Developer("钱七", 17000, 22, "C++"));
company.addEmployee(new Designer("孙八", 14000, 19, "Photoshop"));
company.addEmployee(new Designer("周九", 15000, 21, "Sketch"));
// 生成薪资报表
System.out.println("===== 生成薪资报表 =====");
SalaryReportVisitor salaryVisitor = new SalaryReportVisitor();
company.accept(salaryVisitor);
salaryVisitor.printReport();
// 生成考勤报表
System.out.println("\n\n===== 生成考勤报表 =====");
AttendanceReportVisitor attendanceVisitor = new AttendanceReportVisitor();
company.accept(attendanceVisitor);
attendanceVisitor.printReport();
}
}
优点:
- 符合单一职责原则,让程序具有优秀的扩展性
- 增加新的访问操作很方便
- 将数据结构与数据操作分离
缺点:
- 具体元素对访问者公布细节,违反了迪米特原则
- 违反了依赖倒置原则,依赖了具体类,没有依赖抽象
- 具体元素变更比较困难
总结与最佳实践
在本文中,我们详细介绍了 23 种经典的 GoF(Gang of Four)设计模式在 Java 中的实现和应用。这些设计模式按照其目的可以分为三类:创建型模式、结构型模式和行为型模式。
设计模式分类总结
创建型模式(5种):
- 单例模式(Singleton):确保一个类只有一个实例,并提供全局访问点。
- 工厂方法模式(Factory Method):定义一个创建对象的接口,让子类决定实例化哪一个类。
- 抽象工厂模式(Abstract Factory):提供一个创建一系列相关或依赖对象的接口,而无需指定它们的具体类。
- 建造者模式(Builder):将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。
- 原型模式(Prototype):用原型实例指定创建对象的种类,并通过复制这些原型创建新对象。
结构型模式(7种):
- 适配器模式(Adapter):将一个类的接口转换成客户希望的另一个接口。
- 桥接模式(Bridge):将抽象部分与实现部分分离,使它们都可以独立变化。
- 组合模式(Composite):将对象组合成树形结构以表示"部分-整体"的层次结构。
- 装饰器模式(Decorator):动态地给一个对象添加一些额外的职责。
- 外观模式(Facade):为子系统中的一组接口提供一个一致的界面。
- 享元模式(Flyweight):运用共享技术有效地支持大量细粒度的对象。
- 代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。
行为型模式(11种):
- 责任链模式(Chain of Responsibility):为请求创建一个接收者对象的链。
- 命令模式(Command):将一个请求封装为一个对象,使得可以用不同的请求对客户进行参数化。
- 解释器模式(Interpreter):给定一个语言,定义它的文法表示,并定义一个解释器。
- 迭代器模式(Iterator):提供一种方法顺序访问一个聚合对象中的各个元素。
- 中介者模式(Mediator):用一个中介对象来封装一系列的对象交互。
- 备忘录模式(Memento):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
- 观察者模式(Observer):定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
- 状态模式(State):允许一个对象在其内部状态改变时改变它的行为。
- 策略模式(Strategy):定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。
- 模板方法模式(Template Method):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。
- 访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作。
设计模式的选择与应用
在实际项目中选择和应用设计模式时,应该遵循以下原则:
-
问题驱动:不要为了使用设计模式而使用设计模式。应该先识别问题,然后选择合适的模式来解决问题。
-
简单优先:如果一个简单的解决方案能够满足需求,就不要使用复杂的设计模式。过度设计会增加系统的复杂性。
-
组合使用:设计模式通常不是孤立使用的,多种模式可以组合使用以解决复杂问题。
-
权衡取舍:每种模式都有其优缺点,需要根据具体情况进行权衡。
-
持续重构:随着项目的发展,可能需要重构代码以引入或改变设计模式。
常见设计模式的应用场景
以下是一些常见设计模式在实际 Java 项目中的应用场景:
-
单例模式:数据库连接池、线程池、缓存、日志对象等全局唯一的资源管理。
-
工厂方法和抽象工厂:JDBC 连接不同数据库、创建不同主题的 UI 组件、支持多种格式的文档解析器等。
-
建造者模式:构建复杂对象,如
StringBuilder
、DocumentBuilder
、ORM 框架中的查询构建器等。 -
适配器模式:旧接口适配新接口、第三方库集成、不同数据格式的转换等。
-
装饰器模式:Java I/O 流类库、动态添加功能如日志、事务、缓存等。
-
观察者模式:事件处理系统、MVC 架构中的视图更新、消息订阅发布系统等。
-
策略模式:算法策略选择、支付方式选择、不同的验证规则等。
-
命令模式:任务队列、操作的撤销/重做功能、事务操作等。
-
代理模式:Spring AOP、远程调用(RMI)、延迟加载、访问控制等。
-
模板方法模式:框架中的钩子方法、固定流程的业务逻辑实现等。
设计模式的误区与注意事项
在使用设计模式时,需要避免以下常见误区:
-
过度设计:不要为了使用设计模式而设计,应该根据实际需求选择合适的模式。
-
生搬硬套:不要强行应用不适合的设计模式,这会使代码更加复杂和难以维护。
-
忽略性能影响:某些设计模式可能会对性能产生影响,需要在灵活性和性能之间找到平衡。
-
忽略上下文:设计模式的应用应该考虑项目的具体上下文,包括团队经验、项目规模、维护周期等。
-
缺乏文档:使用设计模式时,应该在代码注释或文档中说明所使用的模式及其理由,以便其他开发人员理解。
结语
设计模式是软件开发中的重要工具,能够帮助我们构建更加灵活、可维护和可扩展的系统。通过学习和应用这些经典的设计模式,我们可以站在巨人的肩膀上,避免重复发明轮子,更高效地解决常见的设计问题。
然而,设计模式并不是银弹,它们是经验的总结,而非教条。在实际应用中,我们需要根据具体问题和场景灵活选择和调整,甚至创造新的模式。真正掌握设计模式的核心在于理解其背后的设计原则和思想,而不仅仅是模式本身的结构和实现。