在这篇文章中,您将了解到SOLID原则。您将理解每个原则,并附有Java代码示例。

SOLID原则是一组五个用于面向对象编程的设计原则。遵循这些原则将帮助您开发健壮的软件。它们将使您的代码更高效、可读且可维护。

SOLID是一个缩写,代表:

  • 单一职责原则
  • 开闭原则
  • 里氏替换原则
  • 接口隔离原则
  • 依赖倒置原则

单一职责原则

单一职责原则指出,每个类必须有单一的、集中的职责,有且只有一个改变的理由。

public class Employee{
  public String getDesignation(int employeeID){ // }
  public void updateSalary(int employeeID){ // }
  public void sendMail(){ // }
}

在上面的例子中,Employee类有一些特定于员工类的行为,比如getDesignationupdateSalary

此外,它还有一个名为sendMail的方法,这与Employee类的职责相悖。

这种行为不是特定于这个类的,拥有它违反了单一职责原则。为了克服这个问题,您可以将sendMail方法移动到一个单独的类中。

下面是如何操作:

public class Employee{
  public String getDesignation(int employeeID){ // }

  public void updateSalary(int employeeID){ 
// }

}

public class NotificationService {
    public void sendMail() { 
// }

}

开闭原则

根据开闭原则,组件必须对扩展开放,但对修改关闭。为了理解这个原则,让我们以一个计算形状面积的类为例。

public class AreaCalculator(){
  public double area(Shape shape){
    double areaOfShape;
    if(shape instanceof Square){
        
// 计算正方形的面积

    } else if(shape instanceof Circle){
        
// 计算圆的面积

    }
    return areaOfShape;
  }

上述例子的问题在于,如果将来需要为新的Shape类型的实例计算面积,你必须通过添加另一个else-if块来修改上述类。对于每个新的Shape类型对象,你都将不得不这样做。

为了克服这个问题,你可以创建一个接口,并让每个Shape实现这个接口。然后,每个类可以提供自己的计算面积实现。这将使你的程序在将来更容易扩展。

interface IAreaCalculator(){
  double area();
}

class Square implements IAreaCalculator{
  @Override
  public double area(){
    System.out.println("Calculating area for Square");
    return 0.0;
   }
}

class Circle implements IAreaCalculator{
  @Override
  public double area(){
    System.out.println("Calculating area for Circle");
    return 0.0;
   }
}

里氏替换原则

里氏替换原则指出,你必须能够用子类对象替换超类对象,而不影响程序的准确性。

abstract class Bird{
   abstract void fly();
}

class Eagle extends Bird {
   @Override
   public void fly() { 
// 一些实现 }

}

class Ostrich extends Bird {
   @Override
   public void fly() { 
// 虚拟实现 }
}

在上面的示例中,Eagle 类和 Ostrich 类都扩展了 Bird 类并重写了 fly() 方法。然而,由于 Ostrich 类不能飞行,因此它被迫提供一个虚拟实现,如果我们用它替换 Bird 类对象,它就不会表现出相同的行为。

这违反了里氏替换原则。为了解决这个问题,我们可以为会飞行的鸟类创建一个单独的类,并让 Eagle 类扩展它,而其他鸟类可以扩展一个不同的类,这个类将不包括任何 fly 行为。

abstract class FlyingBird{
   abstract void fly();
}

abstract class NonFlyingBird{
   abstract void doSomething();
}

class Eagle extends FlyingBird {
   @Override
   public void fly() { // 一些实现 }
}

class Ostrich extends NonFlyingBird {
   @Override
   public void doSomething() { // 一些实现 }
}

接口隔离原则

根据接口隔离原则,你应该构建小而专注的接口,不要强迫客户端实现他们不需要的行为。

一个直接的例子是为计算形状的面积和体积创建一个接口。

interface IShapeAreaCalculator(){
  double calculateArea();
  double calculateVolume();
}

class Square implements IShapeAreaCalculator{
  double calculateArea(){ // 计算面积 }
  double calculateVolume(){ // 虚拟实现 }
}

这个问题在于,如果一个 Square 形状实现了这个接口,那么它被迫实现 calculateVolume() 方法,而这方法它是不需要的。

另一方面,一个Cube可以实现两者。为了克服这个问题,我们可以隔离接口,并有两个分离的接口:一个用于计算面积,另一个用于计算体积。这将允许各个形状决定要实现什么。

interface IAreaCalculator {
    double calculateArea();
}

interface IVolumeCalculator {
    double calculateVolume();
}

class Square implements IAreaCalculator {
    @Override
    public double calculateArea() { // 计算面积 }
}

class Cube implements IAreaCalculator, IVolumeCalculator {
    @Override
    public double calculateArea() { // 计算面积 }

    @Override
    public double calculateVolume() {// 计算体积 }
}

依赖倒置原则

在依赖倒置原则中,高级模块不应该依赖于低级模块。换句话说,你必须遵循抽象,确保松耦合。

public interface Notification {
    void notify();
}

public class EmailNotification implements Notification {
    public void notify() {
        System.out.println("Sending notification via email");
    }
}

public class Employee {
    private EmailNotification emailNotification; 
    public Employee(EmailNotification emailNotification) {
        this.emailNotification = emailNotification;
    }
    public void notifyUser() {
        emailNotification.notify();
    }
}

在给定示例中,Employee 类直接依赖于 EmailNotification 类,这是一个低级模块。这违反了依赖倒置原则。

public interface Notification{
  public void notify();
}

public class Employee{
  private Notification notification;
  public Employee(Notification notification){
      this.notification = notification;
  }
  public void notifyUser(){
    notification.notify();
  }
 }

 public class EmailNotification implements Notification{
    public void notify(){
        // 通过电子邮件实现通知 
    }
 }

 public static void main(String [] args){
    Notification notification = new EmailNotification();
    Employee employee = new Employee(notification);
    employee.notifyUser();
 }

在上面的例子中,我们已经确保了松耦合。Employee 并不依赖于任何具体实现,而是只依赖于抽象(通知接口)。

如果我们需要更改通知方式,我们可以创建一个新的实现,并将其传递给 Employee

结论

总之,通过本文中的简单示例,我们涵盖了SOLID原则的本质。

这些原则是开发高度可扩展和可重用应用程序的基石。

请在领英上与我联系。