接口隔离原则(ISP)
该原则指出较大的接口分为较小的接口。因为实现类只使用需要的方法,我们不应该强迫客户使用他们不想使用的方法。
这也有点类似于单一责任原则。正确的应用程序设计和正确的抽象是接口隔离原则背后的关键。
让我们举个例子。
我们有一个支付接口来代表所有类型的支付。 BankPayment 和 LoanPayment 是 Payment 中实现类。
java
复制代码
public interface Payment { void init(); Object status(); List<Object> getPayments(); } public class LoanPayment implements Payment { @Override public void init() { System.out.println("Initiate LoanPayment..."); } @Override public Object status() { return "LoanPayment Status"; } @Override public List<Object> getPayments() { return Arrays.asList("LoanPayment1", "LoanPayment2"); } } public class BankPayment implements Payment { @Override public void init() { System.out.println("Initiate BankPayment..."); } @Override public Object status() { return "BankPayment Status"; } @Override public List<Object> getPayments() { return Arrays.asList("BankPayment1", "BankPayment2"); } }
想象一下,我们收到一个新要求,需要向 Payment 接口添加一个方法。但是实际上这个方法只有 LoanPayment 类需要持有。那么我们就得修改 Payment 接口了。除了修改 LoanPayment 我们还得修改 BankPayment 类,因为 BankPayment 也实现了 Payment 接口。
新方法将返回付款期限:贷款 => 10 年
java
复制代码
public interface Payment { void init(); Object status(); List<Object> getPayments(); int getTimePeriod(); } public class LoanPayment implements Payment { @Override public void init() { System.out.println("Initiate LoanPayment..."); } @Override public Object status() { return "LoanPayment Status"; } @Override public List<Object> getPayments() { return Arrays.asList("LoanPayment1", "LoanPayment2"); } public int getTimePeriod() { return 10; } } public class BankPayment implements Payment { @Override public void init() { System.out.println("Initiate BankPayment..."); } @Override public Object status() { return "BankPayment Status"; } @Override public List<Object> getPayments() { return Arrays.asList("BankPayment1", "BankPayment2"); } // not needed for BankPayment but we have to override public int getTimePeriod() { retun 0; } }
这样做不好。在这种情况下,一开始的代码设计就很重要了!让我们尝试在这里应用接口隔离原则(ISP)。
java
复制代码
public interface Payment { void init(); Object status(); List<Object> getPayments(); } public interface Loan extends Payment { int getTimePeriod(); } public interface Bank extends Payment { int getOutstandingBalance(); } public class LoanPayment implements Loan { @Override public int getTimePeriod() { return 10; } @Override public void init() { System.out.println("Initiate LoanPayment..."); } @Override public Object status() { return "LoanPayment Status"; } @Override public List<Object> getPayments() { return Arrays.asList("LoanPayment1", "LoanPayment2"); } } public class BankPayment implements Bank { @Override public int getOutstandingBalance() { return 1000; } @Override public void init() { System.out.println("Initiate BankPayment..."); } @Override public Object status() { return "BankPayment Status"; } @Override public List<Object> getPayments() { return Arrays.asList("BankPayment1", "BankPayment2"); } }
这就是设计如何让我们的代码变得更好!我们已经彻底摆脱了 ISP 的困扰。我们使用了更多的接口,并全面地划分了职责。
如果出现与银行支付相关的新要求会怎样?
我们只需要修改 Bank 接口并在 BankPayment 类中重写它,不会影响其他类!
依赖倒置原则(DIP)
该原则指出我们必须使用抽象(抽象类和接口)而不是具体实现。高层模块不应该依赖于低层模块,两者都应该依赖于抽象。
让我在这里用另一个例子来解释。
假设我们要创建一个购物场景,我们需要信用卡或借记卡来购买物品,让我们创建它们并进行购买!
java
复制代码
public class CreditCard { public void doTransaction(double amount) { System.out.println("Transaction with CreditCard: " + amount); } } public class DebitCard { public void doTransaction(double amount) { System.out.println("Transaction with DebitCard: " + amount); } }
商场场景
java
复制代码
public class ShoppingMall { private DebitCard debitCard; public ShoppingMall(DebitCard debitCard) { this.debitCard = debitCard; } public void purchase(double amount) { this.debitCard.doTransaction(amount); } public static void main(String[] args) { DebitCard debitCard = new DebitCard(); ShoppingMall shoppingMall = new ShoppingMall(debitCard); shoppingMall.purchase(10000); } }
你可以在这里看到,DebitCard 作为 ShoppingMall 类的依赖项紧密耦合。我们需要它来执行购买。那么如果有人没有借记卡会怎样?但他/她有信用卡!现在我们再次必须更改 ShoppingMall 类并绑定信用卡而不是借记卡。(代码设计很重要!)
让我们将依赖倒置原则(DIP)应用到购物中心 ShoppingMall。
java
复制代码
public interface BankCard { void doTransaction(double amount); } public class DebitCard implements BankCard { @Override public void doTransaction(double amount) { System.out.println("Transaction with DebitCard: " + amount); } } public class CreditCard implements BankCard { @Override public void doTransaction(double amount) { System.out.println("Transaction with CreditCard: " + amount); } }
我们引入了一个接口作为两张卡的父级,一个 BankCard 接口。我们的新购物中心现在将能够使用任何银行卡,而不是与特定的卡类型紧密结合!请参阅下面的客户端代码。
java
复制代码
public class ShoppingMall { private BankCard bankCard; public ShoppingMall(BankCard bankCard) { this.bankCard = bankCard; } public void purchase(double amount) { this.bankCard.doTransaction(amount); } public static void main(String[] args) { BankCard bankCard1 = new DebitCard(); BankCard bankCard2 = new CreditCard(); ShoppingMall shoppingMall = new ShoppingMall(bankCard1); // ShoppingMall shoppingMall = new ShoppingMall(bankCard2); shoppingMall.purchase(10000); } }
ShoppingMall 现在接受任何卡作为其依赖项。就这样我们实现了最后一个依赖倒置原则(DIP)。
总结
我希望本文我举的例子能够被大家理解,因为我尝试用熟悉的场景来讲解它们。当我第一次读到 SOLID 原则时,它对我来说也像希腊语(很难理解)。但后来我渐渐地理解了他们,我把我理解这些概念的方式也写在这里,所以这篇文章的内容非常丰富。最后,感谢大家阅读。