原来SOLID原则要这么理解!

本文介绍了软件设计中的两个重要原则——开闭原则(OCP)和里氏替换原则(LSP)。开闭原则主张软件实体对扩展开放,对修改关闭,通过接口实现。里氏替换原则强调子类应能替换其基类并保持行为一致,避免破坏原有约定。举例说明了这两个原则的实际应用,以帮助开发者更好地理解和遵循这些设计原则。
摘要由CSDN通过智能技术生成

开闭原则(Open Closed Principle),它的定义是:一个软件实体,如类、模块和函数应该对扩展开放,对修改关闭。简单地说:就是当别人要修改软件功能的时候,使得他不能修改我们原有代码,只能新增代码实现软件功能修改的目的。

这听着有点玄乎,我来举个例子吧。

这段代码模拟的是对于水果剥皮的处理程序。如果是苹果,那么是一种拨皮方法;如果是香蕉,则是另一种剥皮方法。如果以后还需要处理其他水果,那么就会在后面加上很多 if else 语句,最终会让整个方法变得又臭又长。如果恰好这个水果中的不同品种有不同的剥皮方法,那么这里面又会有很多层嵌套。

if(type == apple){
//deal with apple
} else if (type == banana){
//deal with banana
} else if (type == …){
//…
}
可以看得出来,上面这样的代码并没有满足「对拓展开放,对修改封闭」的原则。每次需要新增一种水果,都可以直接在原来的代码上进行修改。久而久之,整个代码块就会变得又臭又长。

如果我们对剥水果皮这件事情做一个抽象,剥苹果皮是一个具体的实现,剥香蕉皮是一个具体的实现,那么写出的代码会是这样的:

public interface PeelOff {
void peelOff();
}

public class ApplePeelOff implement PeelOff{
void peelOff(){
//deal with apple
}
}

public class BananaPeelOff implement PeelOff{
void peelOff(){
//deal with banan
}
}

public class PeelOffFactory{
private Map<String, PeelOff> map = new HashMap();

private init(){
    //init all the Class that implements PeelOff interface 
  }

}

public static void main(){
String type = “apple”;
PeelOff peelOff = PeelOffFactory.getPeelOff(type); //get ApplePeelOff Class Instance.
peelOff.pealOff();
}
上面这种实现方式使得别人无法修改我们的代码,为什么?

因为当需要对西瓜剥皮的时候,他会发现他只能新增一个类实现 PeelOff 接口,而无法再原来的代码上修改。这样就实现了「对拓展开放,对修改封闭」的原则。

里氏替换原则(LSP)
里氏替换原则(LSP)的定义是:所有引用基类的地方必须能透明地使用其子类的对象。简单地说:所有父类能出现的地方,子类就可以出现,并且替换了也不会出现任何错误。 例如下面 Parent 类出现的地方,可以替换成 Son 类,其中 Son 是 Parent 的子类。

Parent obj = new Son();
等价于
Son son = new Son();
这样的例子在 Java 语言中是非常常见的,但其核心要点是:替换了也不会出现任何的错误。这就要求子类的所有相同方法,都必须遵循父类的约定,否则当父类替换为子类时就会出错。 这样说可能还是有点抽象,我举个例子。

public class Parent{
// 定义只能扔出空指针异常
public void hello throw NullPointerException(){
}
}
public class Son extends Parent{
public void hello throw NullPointerException(){
// 子类实现时却扔出所有异常
throw Exception;
}
}
文章首发于【陈树义的博客】,点击跳转到原文超易懂!原来 SOLID 原则要这么理解! - 陈树义的博客
上面的代码中,父类对于 hello 方法的定义是只能扔出空指针异常,但子类覆盖父类的方法时,却扔出了其他异常,违背了父类的约定。那么当父类出现的地方,换成了子类,那么必然会出错。

其实这个例子举得不是很好,因为这个在编译层面可能就有错误。但表达的意思应该是到位了。

而这里的父类的约定,不仅仅指的是语法层面上的约定,还包括实现上的约定。有时候父类会在类注释、方法注释里做了相关约定的说明,当你要覆写父类的方法时,需要弄懂这些约定,否则可能会出现问题。例如子类违背父类声明要实现的功能。比如父类某个排序方法是从小到大来排序,你子类的方法竟然写成了从大到小来排序。

里氏替换原则 LSP 重点强调:对使用者来说,能够使用父类的地方,一定可以使用其子类,并且预期结果是一致的。

接口隔离原则(ISP)
接口隔离原则(Interface Segregation Principle)的定义是:类间的依赖关系应该建立在最小的接口上。简单地说:接口的内容一定要尽可能地小,能有多小就多小。

举个例子来说,我们经常会给别人提供服务,而服务调用方可能有很多个。很多时候我们会提供一个统一的接口给不同的调用方,但有些时候调用方 A 只使用 1、2、3 这三个方法,其他方法根本不用。调用方 B 只使用 4、5 两个方法,其他都不用。接口隔离原则的意思是,你应该把 1、2、3 抽离出来作为一个接口,4、5 抽离出来作为一个接口,这样接口之间就隔离开来了。

那么为什么要这么做呢?我想这是为了隔离变化吧! 想想看,如果我们把 1、2、3、4、5 放在一起,那么当我们修改了 A 调用方才用到 的 1 方法,此时虽然 B 调用方根本没用到 1 方法,但是调用方 B 也会有发生问题的风险。而如果我们把 1、2、3 和 4、5 隔离成两个接口了,我修改 1 方法,绝对不会影响到 4、5 方法。

除了改动导致的变化风险之外,其实还会有其他问题,例如:调用方 A 抱怨,为什么我只用 1、2、3 方法,你还要写上 4、5 方法,增加我的理解成本。调用方 B 同样会有这样的困惑。

在软件设计中,ISP 提倡不要将一个大而全的接口扔给使用者,而是将每个使用者关注的接口进行隔离。
USB Microphone https://www.soft-voice.com/
Wooden Speakers https://www.zeshuiplatform.com/
亚马逊测评 www.yisuping.cn
深圳网站建设www.sz886.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值