在这篇文章中,您将了解到SOLID原则。您将理解每个原则,并附有Java代码示例。
SOLID原则是一组五个用于面向对象编程的设计原则。遵循这些原则将帮助您开发健壮的软件。它们将使您的代码更高效、可读且可维护。
SOLID是一个缩写,代表:
- 单一职责原则
- 开闭原则
- 里氏替换原则
- 接口隔离原则
- 依赖倒置原则
单一职责原则
单一职责原则指出,每个类必须有单一的、集中的职责,有且只有一个改变的理由。
public class Employee{
public String getDesignation(int employeeID){ // }
public void updateSalary(int employeeID){ // }
public void sendMail(){ // }
}
在上面的例子中,Employee
类有一些特定于员工类的行为,比如getDesignation
和updateSalary
。
此外,它还有一个名为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原则的本质。
这些原则是开发高度可扩展和可重用应用程序的基石。
请在领英上与我联系。
Source:
https://www.freecodecamp.org/news/introduction-to-solid-principles/