【七大软件架构设计原则详解】

在这里插入图片描述
在这里插入图片描述

概况

在软件开发中,为了提高软件系统的可维护性与可复用性,增加软件系统的可扩展性与灵活性,程序员要尽量遵循这七条原则去开发程序。遵循设计原则的开发,可以很好地提高软件开发效率、节约软件开发与维护成本。

这七种设计原则的侧重点不同。其中,开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;单一职责原则告诉我们实现类要职责单一;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合度;合成复用原则告诉我们要优先使用组合或者聚合关系复用,少用继承关系复用。

但在实际的软件开发实践中,并不是一定所有代码都遵循设计原则,而是要综合考虑人力、时间和成本,不刻意去追求完美,要在适当的场景下去遵循适用的设计原则。这是一种平衡取舍,可以帮助我们设计出更有质量、更优雅的代码。

七大软件设计原则包括开闭原则、依赖倒置原则、 单一职责原则、接口隔离原则、迪米特法则、里氏替换原则、合成复用原则:

1. 单一职责原则(Single Responsibility Principle, SRP)

一个类应该只有一个引起变化的原因。换句话说,一个类应该只有一个职责。这样做的好处是使代码更加高内聚,修改某一个职责不会影响到其他职责。

public class UserManager {
   
    public void createUser(User user) {
   
        // 创建用户的逻辑
    }

    public void updateUser(User user) {
   
        // 更新用户的逻辑
    }

    public void deleteUser(int userId) {
   
        // 删除用户的逻辑
    }
}

2. 开放封闭原则(Open Closed Principle, OCP)

软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。换句话说,当需求变化时,我们应该尽量通过扩展已有的实体来实现,而不是修改原有的代码。这样做的好处是降低修改代码的风险,并且便于维护和扩展。

public interface Shape {
   
    double calculateArea();
    // 可以添加其他计算相关的方法
}

public class Rectangle implements Shape {
   
    private double width;
    private double height;

    public Rectangle(double width, double height) {
   
        this.width = width;
        this.height = height;
    }

    @Override
    public double calculateArea() {
   
        return width * height;
    }
}

public class Circle implements Shape {
   
    private double radius;

    public Circle(double radius) {
   
        this.radius = radius;
    }

    @Override
    public double calculateArea() {
   
        return Math.PI * radius * radius;
    }
}

3. 里氏替换原则(Liskov Substitution Principle, LSP)

子类必须完全实现父类的方法,并且在使用父类的地方可以完全替代父类。换句话说,子类不应该破坏父类的原有行为和约束。这样做的好处是提高代码的可复用性,并且保持代码的稳定性。

public class Rectangle {
   
    protected double width;
    protected double height;

    public Rectangle(double width, double height) {
   
        this.width = width;
        this.height = height;
    }

    public double getWidth() {
   
        return width;
    }

    public void setWidth(double width) {
   
        this.width = width;
    }

    public double getHeight() {
   
        return height;
    }

    public void setHeight(double height) {
   
        this.height = height;
    }

    public double calculateArea() {
   
        return width * height;
    }
}

public class Square extends Rectangle {
   
    public Square(double side) {
   
        super(side, side);
    }

    @Override
    public void setWidth(double width) {
   
        super.setWidth(width);
        super.setHeight(width);
    }

    @Override
    public void setHeight(double height) {
   
        super.setWidth(height);
        super.setHeight(height);
    }
}

4. 依赖倒置原则(Dependency Inversion Principle, DIP)

抽象不应该依赖于具体实现,而是具体实现应该依赖于抽象。换句话说,高层模块不应该依赖于低层模块,两者都应该依赖于抽象。这样做的好处是减少模块间的耦合,提高代码的灵活性和可测试性。

public interface Database {
   
    void saveData(String data);
}

public class MySQLDatabase implements Database {
   
    @Override
    public void saveData(String data) {
   
        // 使用MySQL数据库保存数据的逻辑
    }
}

public class OracleDatabase implements Database {
   
    @Override
    public void saveData(String data) {
   
        // 使用Oracle数据库保存数据的逻辑
    }
}

public class DataManager {
   
    private Database database;

    public DataManager(Database database) {
   
        this.database = database;
    }

    public void saveData(String data) {
   
        database.saveData(data);
    }
}

5. 接口隔离原则(Interface Segregation Principle, ISP)

任何一个客户端不应该依赖它不需要的接口。换句话说,一个类不应该强迫它的客户端依赖于它们不需要的方法。这样做的好处是减少接口的冗余和复杂性,增强代码的可读性。

public interface ReportGenerator {
   
    void generatePDFReport();
    void generateCSVReport();
    void generateHTMLReport();
}

public class PDFReportGenerator implements ReportGenerator {
   
    @Override
    public void generatePDFReport() {
   
        // 生成PDF报告的逻辑
    }

    @Override
    public void generateCSVReport() {
   
        throw new UnsupportedOperationException();
    }

    @Override
    public void generateHTMLReport() {
   
        throw new UnsupportedOperationException();
    }
}

public class CSVReportGenerator implements ReportGenerator {
   
    @Override
    public void generatePDFReport() {
   
        throw new UnsupportedOperationException();
    }

    @Override
    public void generateCSVReport() {
   
        // 生成CSV报告的逻辑
    }

    @Override
    public void generateHTMLReport() {
   
        throw new UnsupportedOperationException();
    }
}

6. 迪米特法则(Law of Demeter, LoD)

一个对象应该对其他对象有尽可能少的了解。换句话说,一个对象应该只与其直接的朋友进行交流,不和陌生的对象进行交流。这样做的好处是减少代码的耦合和依赖,提高代码的灵活性和可维护性。

public class Teacher {
   
    private String name;

    public Teacher(String name) {
   
        this.name = name;
    }

    public void giveHomework(Student student) {
   
        student.doHomework();
    }
}

public class Student {
   
    private String name;

    public Student(String name) {
   
        this.name = name;
    }

    public void doHomework() {
   
        // 做作业的逻辑
    }
}

在这里插入图片描述

7. 合成复用原则(Composite Reuse Principle, CRP)

尽量使用合成/聚合,而不是继承。换句话说,尽量通过组合和委托来实现代码的复用,而不是通过继承来实现。这样做的好处是降低代码的耦合度,增强代码的灵活性和可维护性。

public class Car {
   
    private Engine engine;

    public Car(Engine engine) {
   
        this.engine = engine;
    }

    public void start() {
   
        engine.start();
    }
}

public interface Engine {
   
    void start();
}

public class ElectricEngine implements Engine {
   
    @Override
    public void start() {
   
        // 电动引擎启动的逻辑
    }
}

public class GasolineEngine implements Engine {
   
    @Override
    public void start() {
   
        // 汽油引擎启动的逻辑
    }
}

总结

上述软件设计七大原则可以使用一句话概括,如下所示:

设计原则 一句话归纳 目的
开闭原则 对扩展开放,对修改关闭 降低维护带来的新风险
依赖倒置原则 高层不应该依赖底层 更利于代码结构的升级扩展
单一职责原则 一个类只干一件事 便于理解,提高代码的可读性
接口隔离原则 一个接口只干一件事 功能解耦,高聚合、低耦合
迪米特法则 不该知道的,不要知道 只和朋友交流,不喝默认人说话,减少代码臃肿
里式替换法则 子类重写方法功能发生变化,不应该影响父类方法的含义 防止继承泛滥
合成复用原则 尽量使用组合实现代码复用,而不是用继承 降低代码耦合

相关推荐

  1. 详细介绍设计模式原则

    2024-02-22 09:58:01       24 阅读
  2. 设计模式> 原则

    2024-02-22 09:58:01       32 阅读
  3. 设计模式——原则

    2024-02-22 09:58:01       31 阅读
  4. 设计模式之设计原则

    2024-02-22 09:58:01       27 阅读
  5. 软件架构设计的核心步骤详解

    2024-02-22 09:58:01       20 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-22 09:58:01       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-22 09:58:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-22 09:58:01       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-22 09:58:01       20 阅读

热门阅读

  1. 人工智能与开源机器学习框架

    2024-02-22 09:58:01       31 阅读
  2. [OpenGL教程05 ] glAccum() 函数对累积缓存设置

    2024-02-22 09:58:01       24 阅读
  3. spring缓存的使用

    2024-02-22 09:58:01       28 阅读
  4. 保存Json对象到数据库

    2024-02-22 09:58:01       31 阅读
  5. LeetCode--代码详解 4.寻找两个正序数组的中位数

    2024-02-22 09:58:01       26 阅读
  6. Docker实战之下载Mysql、Redis、Zimg

    2024-02-22 09:58:01       38 阅读
  7. k8s-权限管理

    2024-02-22 09:58:01       32 阅读