本文翻译自国外论坛 medium,原文地址:salithachathuranga94.medium.com/solid-princ…
本文将带领大家学习在日常编程中如何使用 SOLID 原则。
如果你是一名优秀的编程人员,那么我要讨论的内容应该是一个众所周知的话题!废话不多说,让我们进入主题。
SOLID 原则由 Robert C. Martin 提出。它们是创建更易于维护、更易于理解和更灵活的软件代码的设计原则。这些经验法则帮助我们以更少的复杂性来编写我们的项目代码。SOLID 原则五个单词含义如下:
- 单一职责原则 (SRP) [ S ]
- 开闭原理 (OCP) [ O ]
- 里氏替换原理 (LSP) [ L ]
- 接口隔离原则 (ISP) [ I ]
- 依赖倒置原则 (DIP) [ D
现在我们用实际例子来一一列举。
单一职责原则(SRP)
该原则规定每个 Java 类必须执行单一功能。在这里单一功能意味着:类必须执行只属于该类的操作。
假设我们有一个名为 BankService 的类。在应用单一职责原则(SRP)之前会是这样的。存款、取款、发送通知、打印存折等所有操作均由 BankService 完成。这样 BankService 类就具有多个彼此不相关的职责。
java
复制代码
public class BankService { public void withdraw(double amount) { System.out.println("Withdraw money : " + amount); } public void deposit(double amount) { System.out.println("Deposit money : " + amount); } public String getLoanInfo(String loanType) { if (loanType.equals("professional")) { return "Professional Loan"; } else if (loanType.equals("home")) { return "Home Loan"; } else { return "Personal Loan"; } } public void printPassbook() { System.out.println("Printing Book Details..."); } public void sendOTP(String medium) { if (medium.equals("mobile")) { System.out.println("Sending OTP to mobile"); } else if (medium.equals("email")) { System.out.println("Sending OTP to email"); } else { System.out.println("Not a valid medium"); } } }
让我们将单一职责原则(SRP)应用于 BankService。我们可以将职责划分为多组服务。
java
复制代码
// BankService public class BankService { public void withdraw(double amount) { System.out.println("Withdraw money : " + amount); } public void deposit(double amount) { System.out.println("Deposit money : " + amount); } } // LoanService public class LoanService { public String getLoanInfo(String loanType) { if (loanType.equals("professional")) { return "Professional Loan"; } else if (loanType.equals("home")) { return "Home Loan"; } else { return "Personal Loan"; } } } // PrinterService public class PrinterService { public void printPassbook() { System.out.println("Printing Book Details..."); } } // NotificationService public class NotificationService { public void sendOTP(String medium) { if (medium.equals("mobile")) { System.out.println("Sending OTP to mobile"); } else if (medium.equals("email")) { System.out.println("Sending OTP to email"); } else { System.out.println("Not a valid medium"); } } }
现在你可以看到每个类都在执行自己的操作。这样代码看起来更加清晰易懂。这就是单一职责原则(SRP)的意义!
开闭原则(OCP)
该原则规定,当有新需求到来,模块应该对扩展开放,对修改关闭。这样我们应该就能够在现有代码的基础上添加扩展,而不改变原来的基本实现,这使得我们更容易扩展逻辑。
假设我们有一个名为 NotificationService 的服务可以向各种媒介发送通知。我们有两种发送 OTP 通知的方法。他们是手机和电子邮件。如果出现通过 WhatsApp 发送 OTP 通知的新要求,会发生什么情况。想象一下,我们应该做什么?我们只能修改原来 NotificationService 的代码!这就违反了开闭原则(OCP)!
让我们将开闭原则(OCP)应用到这个场景中。我将重新实现这个 NotificationService 类,准确来说 NotificationService 应该是一个接口。然后我将在另外 3 个服务中实现该接口,分别为 MobileNotificationService、EmailNotificationService 和 WhatsAppNotificationService。
java
复制代码
public interface NotificationService { void sendOTP(String medium); void sendTransactionHistory(String medium); } public class MobileNotificationService implements NotificationService { @Override public void sendOTP(String medium) { System.out.println("Sending OTP Number Message to: " + medium); } @Override public void sendTransactionHistory(String medium) { System.out.println("Sending Transactions Message to: " + medium); } } public class EmailNotificationService implements NotificationService { @Override public void sendOTP(String medium) { System.out.println("Sending OTP Number Email to: " + medium); } @Override public void sendTransactionHistory(String medium) { System.out.println("Sending Transactions Email to: " + medium); } } public class WhatsAppNotificationService implements NotificationService { @Override public void sendOTP(String medium) { System.out.println("Sending OTP Number to: " + medium); } @Override public void sendTransactionHistory(String medium) { System.out.println("Sending Transactions Details to: " + medium); } }
如果我想发送所有 3 种类型的通知,我可以这样做。
如果又有另一种类型的新媒介需要发送那会发生什么?我们只需要创建另一个服务,从 NotificationService 实现它并完成与新媒介相关的逻辑就行!
这就是所有代码!我们已经成功应用开闭原则(OCP)。
里氏替换原则(LSP)
据说这是大多数开发人员最难理解的原则。这是由芭芭拉·利斯科夫(Barbara Liskov)介绍的。它适用于继承,子类必须完全可替换其父类。
如果类 A 是类 B 的子类型,那么我们应该能够在不中断程序行为的情况下用 A 替换 B。
让我们通过一个例子来理解这一点,但是我要提醒你,这个原则会让文章变得很长。🤔
假设我们要管理多种类型的社交媒体平台。它们是 Facebook、Instagram 和 WhatsApp。
因此,SocialMedia 类有 3 个方法,分别称为 chat()、publish() 和 groupCall()。为了展现里氏替换原则(LSP)的作用,我将直接用 Facebook、Instagram、WhatsApp 3 个类来实现这一点。
java
复制代码
public abstract class SocialMedia { abstract void chat(String user); abstract void publish(Object post); abstract void groupCall(String... users); } public class Facebook extends SocialMedia { @Override void chat(String user) { } @Override void publish(Object post) { } @Override void groupCall(String... users) { } } public class Instagram extends SocialMedia { @Override void chat(String user) { } @Override void publish(Object post) { } @Override void groupCall(String... users) { } } public class WhatsApp extends SocialMedia { @Override void chat(String user) { } @Override void publish(Object post) { } @Override void groupCall(String... users) { } }
SocialMedia 是一个抽象类,所有其他平台都是它的子类。预期的逻辑现已实现。那么这里出了什么问题呢?
你是否注意到,这样做的话,所有平台都必须实现这三个方法,即使该平台不支持此方法!让我解释一下
Facebook:支持所有方法 chat()、publish() 和 groupCall()。
WhatsApp:不支持发布帖子 publish()。
Instagram:不支持群组通话 groupCall()。
所以在这种情况下,Instagram 或 WhatsApp 不能完全替代 SocialMedia 类!
现在让我们在这里应用里氏替换原则(LSP)。
java
复制代码
public interface SocialMedia { void chat(String user); } public interface PostManager { void publish(Object post); } public interface VideoCallManager { void groupCall(String... users); } public class Facebook implements SocialMedia, PostManager { @Override public void publish(Object post) { System.out.println("Publishing a post on Facebook: " + post); } @Override public void chat(String user) { System.out.println("Chatting on Facebook with: " + user); } } public class WhatsApp implements SocialMedia, VideoCallManager { @Override public void chat(String user) { System.out.println("Chatting on WhatsApp with: " + user); } @Override public void groupCall(String... users) { System.out.println("Taking a Group Call on WhatsApp with: " + Arrays.toString(users)); } }
你现在可以看到 SocialMedia 是一个具有单一职责的接口,包含 chat() 方法。因此我们有单独的界面来管理视频通话和发布帖子。这样所有子类:Facebook 和 WhatsApp 都会执行它们只能执行的操作!
- WhatsApp 是 SocialMedia 和 VideoCallManager 的子类
- Facebook 是 SocialMedia 和 PostManager 的子类
让我们检查一下定义:
如果 WhatsApp 类是 SocialMedia 类的子类,那么我们应该能够在不中断程序行为的情况下用 WhatsApp 替换 SocialMedia。
这就是里氏替换原则(LSP)的全部内容!!!讲解完了!