【七大软件架构设计原则详解】
  TEZNKK3IfmPf 2024年04月19日 16 0

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

概况

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

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

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

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

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) {
         = name;
    }

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

public class Student {
    private String name;

    public Student(String 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() {
        // 汽油引擎启动的逻辑
    }
}

总结

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

设计原则

一句话归纳

目的

开闭原则

对扩展开放,对修改关闭

降低维护带来的新风险

依赖倒置原则

高层不应该依赖底层

更利于代码结构的升级扩展

单一职责原则

一个类只干一件事

便于理解,提高代码的可读性

接口隔离原则

一个接口只干一件事

功能解耦,高聚合、低耦合

迪米特法则

不该知道的,不要知道

只和朋友交流,不喝默认人说话,减少代码臃肿

里式替换法则

子类重写方法功能发生变化,不应该影响父类方法的含义

防止继承泛滥

合成复用原则

尽量使用组合实现代码复用,而不是用继承

降低代码耦合

 

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2024年04月19日 0

暂无评论

TEZNKK3IfmPf