news 2026/5/24 17:15:03

手把手吃透设计模式内功:七大原则代码解析与重构指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
手把手吃透设计模式内功:七大原则代码解析与重构指南

事实上,许多学习者将重点放在了记忆“招式”(即具体模式)上,导致即便背熟了众多模式,在实际开发中仍鲜有应用。设计模式真正的核心在于其背后的设计原则。所有经典的设计模式,无一不是在这些基本原则的指导思想下衍生出来的。因此,欲成高手,必先修炼好“内功”。

下面,我将系统阐述构成设计模式基石的七大设计原则。

一、单一职责原则

定义:一个类应该只有一个引起它变化的原因。

解读:通俗来讲,如果你能找到两种及以上不同类型的理由去修改某个类,那么这个类就违反了单一职责原则。

示例剖析:

```java

class UserService {

public void register(String username, String password) {

// 1. 校验用户名和密码

if (username == null || password.length() < 6) {

throw new IllegalArgumentException("参数错误");

}

// 2. 保存用户到数据库

System.out.println("save user to mysql");

// 3. 发送欢迎短信

System.out.println("send sms to user");

// 4. 打印日志

System.out.println("log register success");

}

}

```

上述 `UserService` 类至少面临四种独立的修改原因:

1. 产品需求变化:密码规则调整为数字+字母组合。

2. 运维需求变化:日志需同时输出至本地与远程日志系统。

3. 技术架构变化:数据库从 MySQL 迁移至 Oracle。

4. 运营需求变化:欢迎通知从短信改为邮件。

这四种毫无关联的变化都可能导致修改同一个类,若系统中有多个 `Service`,修改将变得异常繁琐且风险极高。设计模式的目标之一,正是将变化的影响局部化,最大限度减少修改范围。

重构方案:将不同变化的职责封装到独立的类中。

```java

class UserService {

private UserValidator validator = new UserValidator();

private UserRepository repository = new UserRepository();

private Notifier notifier = new Notifier();

private Logger logger = new Logger();

public void register(String username, String password) {

validator.validate(username, password); // 封装规则变化

repository.save(username, password); // 封装存储变化

notifier.notifyUser(username); // 封装通知变化

logger.log("register success"); // 封装日志变化

}

}

```

策略模式即是单一职责原则的一个典型应用。

二、开闭原则

定义:对扩展开放,对修改关闭。

解读:系统设计应允许在不修改现有稳定代码的前提下,通过扩展来增加新功能。

此原则与单一职责原则相辅相成:后者负责封装变化,前者则倡导通过扩展而非修改来应对变化。

反面示例:

```java

class PayService {

public void pay(String type, int amount) {

if ("alipay".equals(type)) {

System.out.println("use alipay");

} else if ("wechat".equals(type)) {

System.out.println("use wechat");

}

// 每新增一种支付方式,都需要修改此方法,添加一个else if

}

}

```

此种设计会导致类不断膨胀,难以维护。

遵循开闭原则的重构:

```java

// 定义抽象策略

interface PayStrategy {

void pay(int amount);

}

// 具体策略实现

class AliPay implements PayStrategy {

public void pay(int amount) {

System.out.println("alipay " + amount);

}

}

class WeChatPay implements PayStrategy {

public void pay(int amount) {

System.out.println("wechat " + amount);

}

}

// 上下文,依赖抽象

class PayService {

private PayStrategy strategy;

public PayService(PayStrategy strategy) {

this.strategy = strategy;

}

public void pay(int amount) {

strategy.pay(amount);

}

}

```

此后新增支付方式(如 `BankPay`),只需实现 `PayStrategy` 接口即可,`PayService` 核心逻辑无需改动。

策略模式、工厂模式、装饰器模式、观察者模式等都是开闭原则的典型体现。

三、里氏替换原则

定义:子类对象必须能够替换其父类对象,且替换后程序的正确性不被破坏。

解读:任何使用父类类型的地方,都应能透明地替换为子类对象。

违反LSP的示例:

```java

class Employee { // 全职员工

public double calculateSalary(double baseSalary) {

return baseSalary; // 全职工资 = 基本工资

}

}

class PartTimeEmployee extends Employee { // 兼职员工

@Override

public double calculateSalary(double baseSalary) {

return baseSalary 0.5; // 兼职按半薪算

}

}

// 使用方法

public void printAnnualSalary(Employee employee) {

// 期望年薪 = 月薪 12

System.out.println(employee.calculateSalary(1000) 12);

}

```

当 `PartTimeEmployee` 实例传入 `printAnnualSalary` 方法时,计算出的“年薪”是基于错误假设的(兼职可能干不满12个月),程序行为出现错误。这说明 `PartTimeEmployee` 并不是 `Employee` 合适的子类。

遵循LSP的设计:

应基于共同行为抽象接口,而非不恰当的继承。

```java

interface SalaryCalculator {

double calculateSalary(double baseSalary);

}

class FullTimeSalaryCalculator implements SalaryCalculator {

public double calculateSalary(double baseSalary) { return baseSalary; }

}

class PartTimeSalaryCalculator implements SalaryCalculator {

public double calculateSalary(double baseSalary) { return baseSalary 0.5; }

}

```

策略模式、模板方法模式、装饰器模式等都体现了LSP思想,确保子类或具体实现能安全替换父类或接口。

四、依赖倒置原则

定义:

1. 高层模块不应依赖低层模块,二者都应依赖抽象。

2. 抽象不应依赖细节,细节应依赖抽象。

解读:高层业务逻辑应依赖于接口(抽象),而非具体的实现类。

反面示例:

```java

class OrderService {

private PayService payService = new PayService();

public void checkout(double amount, String type) {

if (type.equals("alipay")) {

payService.payByAliPay(amount);

} else if (type.equals("wechat")) {

payService.payByWeChat(amount);

}

}

}

```

`OrderService`(高层)直接依赖了具体的 `PayService` 及其方法。新增支付方式需要同时修改高层和低层代码。

遵循DIP的重构:

```java

// 抽象

interface PayStrategy {

void pay(double amount);

}

// 具体实现

class AliPay implements PayStrategy { / ... / }

class WeChatPay implements PayStrategy { / ... / }

// 高层模块依赖抽象

class OrderService {

private PayStrategy payStrategy;

public OrderService(PayStrategy payStrategy) { // 依赖注入

this.payStrategy = payStrategy;

}

public void checkout(double amount) {

payStrategy.pay(amount); // 只调用抽象方法

}

}

// 使用

OrderService order1 = new OrderService(new AliPay());

order1.checkout(100);

```

此原则保证了当底层实现变化时,高层业务逻辑保持稳定,系统可通过扩展灵活适应变化。

依赖注入、策略模式、工厂模式是此原则的主要应用。

五、接口隔离原则

定义:客户端不应被迫依赖它不使用的接口方法。

解读:接口应当职责单一、粒度细小,只暴露客户端真正需要的方法,避免“胖接口”。

反面示例:

```java

public interface UserService{

void addUser(User user);

void log(String tag, String message); // 与用户核心业务无关

void uploadFile(File file); // 与用户核心业务无关

}

```

`UserService` 接口混杂了日志、文件上传等不相关的职责,导致实现类被迫实现所有方法,降低了内聚性。

遵循ISP的重构:

```java

public interface UserService{

void addUser(User user);

void updateUser(User user);

User findById(Integer id);

void delete(Integer id);

}

public interface LogService{

void log(String tag, String message);

}

public interface UploadService{

void uploadFile(File file);

}

```

将不同业务的接口分离,使得系统更清晰,也提高了接口的复用性。

策略模式、装饰器模式、适配器模式都体现了接口隔离的思想。

六、迪米特法则(最少知识原则)

定义:一个对象应尽可能少地了解其他对象,只与“直接的朋友”通信。

解读:降低类之间的耦合度,避免过深的链式调用。

违反示例:

```java

class User {

private Address address;

public Address getAddress() { return address; }

}

class Address {

private String city;

public String getCity() { return city; }

}

class OrderService {

public void printUserCity(User user) {

// 深层调用:user > address > city

System.out.println(user.getAddress().getCity());

}

}

```

`OrderService` 不仅依赖 `User`,还间接依赖了 `Address` 的内部细节。一旦 `Address` 结构变化,`OrderService` 也可能需要修改。

遵循迪米特法则的重构:

```java

class User {

private Address address;

public String getCity() { // 封装对Address的访问

return address.getCity();

}

}

class OrderService {

public void printUserCity(User user) {

// 只与User交互,不感知Address细节

System.out.println(user.getCity());

}

}

```

此法有效防止了 `a.getB().getC().doSomething()` 这类深层链式调用,降低了模块间的耦合,使系统更易维护。

外观模式、代理模式是该法则的典型应用。

七、合成复用原则

定义:优先使用对象组合,而非类继承,来达到复用的目的。

解读:组合比继承具有更大的灵活性,能降低类之间的耦合度。

反面示例(过度使用继承):

```java

class Report {

public void generatePDF() { System.out.println("生成PDF报表"); }

public void generateExcel() { System.out.println("生成Excel报表"); }

}

class LoggedReport extends Report { // 通过继承添加日志功能

@Override

public void generatePDF() {

System.out.println("记录日志");

super.generatePDF();

}

@Override

public void generateExcel() {

System.out.println("记录日志");

super.generateExcel();

}

}

```

`LoggedReport` 与 `Report` 紧密耦合。若 `Report` 的方法签名或行为改变,`LoggedReport` 必须同步修改,且无法灵活地复用其他类型的“增强”功能(如加密、压缩等)。

遵循合成复用原则的重构:

```java

class Report {

public void generatePDF() { / ... / }

public void generateExcel() { / ... / }

}

class Logger { // 独立的日志功能

public void log(String msg) { System.out.println("记录日志: " + msg); }

}

class ReportService { // 通过组合复用

private Report report;

private Logger logger;

public ReportService(Report report, Logger logger) {

this.report = report;

this.logger = logger;

}

public void generatePDF() {

logger.log("生成PDF");

report.generatePDF();

}

public void generateExcel() {

logger.log("生成Excel");

report.generateExcel();

}

}

```

通过组合,可以更灵活地装配不同功能,且 `Report` 和 `Logger` 可以独立变化和复用。

总结

七大设计原则构成了高质量软件设计的基石。在日常开发中,时刻以这些原则为指导,能够使你的程序结构更清晰、代码更简洁、模块更独立,从而显著降低维护成本,提升系统的可扩展性与健壮性。掌握这些“内功”,远比单纯记忆设计模式“招式”更为重要。

来源:小程序app开发|ui设计|软件外包|IT技术服务公司-木风未来科技-成都木风未来科技有限公司

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/13 12:44:15

【课程设计/毕业设计】基于springboot美发门店管理系统设计与实现基于springboot的美发商城系统【附源码、数据库、万字文档】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/5/1 7:00:20

Java计算机毕设之基于springboot的美发商城系统美发产品管理洗护 / 染烫 / 造型工具(完整前后端代码+说明文档+LW,调试定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/5/10 18:20:41

Java毕设项目:基于SpringBoot的植物知识管理与分享平台的设计与实现(源码+文档,讲解、调试运行,定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/5/23 14:58:42

反射2-获取class对象的三种方式

一、反射 在Java中&#xff0c;Class对象是反射机制的起点&#xff0c;它代表了JVM中加载的类的元数据。获取Class对象就像拿到了"类的身份证"&#xff0c;有了它才能进行反射操作&#xff08;如动态创建对象、调用方法、修改字段等&#xff09;。 通俗比喻&#xf…

作者头像 李华
网站建设 2026/5/22 20:16:16

新品限免|国产大模型工程化实战:GLM-4.7与MiniMax M2.1 免费选型对比

一、技术定位与核心差异解析 在参与多个企业级项目开发后&#xff0c;我深刻体会到GLM-4.7与MiniMax M2.1在工程化落地中的差异化表现。这两款国产大模型已形成互补的技术生态&#xff0c;分别针对不同开发场景进行了深度优化。 GLM-4.7&#xff1a;复杂工程任务的一次性交付引…

作者头像 李华
网站建设 2026/5/23 13:25:52

vue基于python的民宿房间预订推荐系统的设计与实现_7r8s9b63(pycharm django flask)

目录已开发项目效果实现截图开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;已开发项目效果实现截图 同行可拿货,招校园代理 vue基于python的民宿房间预订推荐系统的设计与实现_7r8s9b63(…

作者头像 李华