面向对象的六大设计原则简称为SOLID原则,每个原则都有助于创建更加健壮、可维护和可扩展的软件系统。以下是对每个原则的详细介绍,以及相应的示例代码和抽象的结构表述。

本文将以尽可能少的文字,带你快速理解六大设计原则,不信?那就开始吧👇👇👇

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


一个类只应当有一个引起它变化的原因,即一个类只负责一个职责。

示例代码:

// 违反单一职责原则的类
public class Order {
    public void addOrderItem(OrderItem item) {
        // 添加订单项
    }

    public void calculateTotal() {
        // 计算总价
    }

    public void printOrder() {
        // 打印订单
    }

    public void saveOrderLog() {
        // 保存订单日志
    }
}

// 遵循单一职责原则的类
public class Order {
    public void addOrderItem(OrderItem item) {
        // 添加订单项
    }

    public void calculateTotal() {
        // 计算总价
    }
}

public class OrderPrinter {
    public void printOrder(Order order) {
        // 打印订单
    }
}

public class OrderLogger {
    public void saveOrderLog(Order order) {
        // 保存订单日志
    }
}

结构表述:

Order ----> addOrderItem(), calculateTotal()
OrderPrinter ----> printOrder()
OrderLogger ----> saveOrderLog()

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


软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。 示例代码:

// 支持开闭原则的图形绘制系统
public interface Shape {
    void draw();
}

public class Circle implements Shape {
    public void draw() {
        System.out.println("Drawing Circle");
    }
}

public class Rectangle implements Shape {
    public void draw() {
        System.out.println("Drawing Rectangle");
    }
}

// 扩展新功能
public class Triangle implements Shape {
    public void draw() {
        System.out.println("Drawing Triangle");
    }
}

public class ShapeDrawer {
    public void drawShapes(List<Shape> shapes) {
        for (Shape shape : shapes) {
            shape.draw();
        }
    }
}

结构表述:

Shape <--- Circle
      <--- Rectangle
      <--- Triangle
ShapeDrawer ----> drawShapes()

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


子类型必须能够替换掉它们的基类型。

示例代码:

public class Bird {
    public void fly() {
        System.out.println("Bird is flying");
    }
}

public class Sparrow extends Bird {
    @Override
    public void fly() {
        System.out.println("Sparrow is flying");
    }
}

// 注意:企鹅不能飞,因此不应该继承Bird类
public class Penguin {
    public void swim() {
        System.out.println("Penguin is swimming");
    }
}

结构表述:

Bird ----> fly()
   ^
   |
Sparrow ----> fly()

Penguin ----> swim()

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


不应该强迫客户端依赖于它们不使用的方法。

示例代码:

// 违反接口隔离原则的接口
public interface Worker {
    void work();
    void eat();
}

// 遵循接口隔离原则的接口
public interface Workable {
    void work();
}

public interface Eatable {
    void eat();
}

public class WorkerImpl implements Workable, Eatable {
    public void work() {
        System.out.println("Worker is working");
    }

    public void eat() {
        System.out.println("Worker is eating");
    }
}

public class Robot implements Workable {
    public void work() {
        System.out.println("Robot is working");
    }
}

结构表述:

Workable ----> work()
      ^     ^
      |     |
Eatable ----> eat()
      ^
      |
WorkerImpl
Robot

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


高层模块不应该依赖于低层模块,二者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。

示例代码:

// 遵循依赖倒置原则的订单处理系统
public interface PaymentProcessor {
    void processPayment(double amount);
}

public class PaypalProcessor implements PaymentProcessor {
    public void processPayment(double amount) {
        System.out.println("Processing payment through PayPal: " + amount);
    }
}

public class OrderService {
    private PaymentProcessor paymentProcessor;

    public OrderService(PaymentProcessor paymentProcessor) {
        this.paymentProcessor = paymentProcessor;
    }

    public void processOrder(double amount) {
        paymentProcessor.processPayment(amount);
    }
}

结构表述:

OrderService ----> PaymentProcessor
                    ^
                    |
              PaypalProcessor ----> processPayment()

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


一个对象应该对其他对象有尽可能少的了解,只与直接的朋友通信。这意味着对象不应调用其他对象的内部细节(方法或属性),而应通过友好的接口访问。

示例代码:

// 遵循迪米特法则的例子
public class Engine {
    public void start() {
        System.out.println("Engine started");
    }
}

public class Car {
    private Engine engine;

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

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

public class Driver {
    public void drive(Car car) {
        car.start();
    }
}

在上面的代码中,Driver类直接与Car交互,而不是直接与Engine交互。这样,DriverEngine之间的耦合度降低,提高了系统的可维护性。

结构表述:

Driver ----> drive(Car)
Car ----> start()
        Engine ----> start()

总结


面向对象的六大原则(SOLID原则)旨在提高代码的可维护性、可读性和可扩展性。以下是每个原则的简要总结:

  • 单一职责原则(SRP):一个类只应该有一个引起它变化的原因。
  • 开闭原则(OCP):软件实体应该对扩展开放,对修改关闭。
  • 里氏替换原则(LSP):子类型必须能够替换掉它们的基类型。
  • 接口隔离原则(ISP):不应该强迫客户端依赖于它们不使用的方法。
  • 依赖倒置原则(DIP):高层模块不应该依赖于低层模块,二者都应该依赖于抽象。
  • 迪米特法则(LoD):一个对象应该对其他对象有尽可能少的了解,只与直接的朋友通信。