理论五 - 七 接口和抽象类的区别、为什么基于接口而非实现编程、为何说要多用组合少用继承

理论五:接口vs抽象类的区别?如何用普通的类模拟抽象类和接口?

  1. 抽象类和接口的区别

    • 语法上:

      • 抽象类不允许被实例化,只能被继承。它可以包含属性和方法。方法既可以包含代码实现,也可以不包含代码实现。不包含代码实现的方法叫作抽象方法。子类继承抽象类,必须实现抽象类中的所有抽象方法。

      • 接口不能包含属性,只能声明方法,方法不能包含代码实现。类实现接口的时候,必须实现接口中声明的所有方法。

        • 抽象类实际上就是类,只不过是一种特殊的类,这种类不能被实例化为对象,只能被子类继承。我们知道,继承关系是一种 is-a 的关系,那抽象类既然属于类,也表示一种 is-a 的关系。
        • 接口表示一种 has-a 关系,表示具有某些功能。对于接口,有其它更加形象的叫法,比如协议/约定/规范。
  2. 抽象类和接口存在的意义

    • 抽象类是对成员变量和方法的抽象,是一种 is-a 关系,是为了解决代码复用问题。

    • 接口仅仅是对方法的抽象,是一种 has-a 关系,表示具有某一组行为特性,是为了解决解耦问
      题,隔离接口和具体的实现,提高代码的扩展性。

  3. 抽象类和接口的应用场景区别

    • 如果要表示一种 is-a 的关系,并且是为了解决代码复用问题,我们就用抽象类

    • 如果要表示一种 has-a 关系,并且是为了解决抽象而非代码复用问题,那我们就用接口。

    • 如何模拟抽象类和接口两个语法概念?

      • 根据定义来:如用C++实现,C++有抽象类,没接口,那么实现接口根据定义来我们只需要将这个类的构造函数声明为 protected 访问权限就可以了。

理论六:为什么基于接口而非实现编程?有必要为每个类都定义接口吗?

  • 如何解读原则中的“接口”二字?

    • “基于接口而非实现编程”,这条原则的另一个表述方式,是“基于抽象而非实现编程”。
      从本质上来看,“接口”就是一组“协议”或者“约定”,是功能提供者提供给使用者的一个“功能列表”。在编程语言里实现为编程语言中的接口或者抽象类。
  • 如何将这条原则应用到实战中?

    • 我们在做软件开发的时候,一定要有抽象意识、封装意识、接口意识。越抽象、越顶层、越脱离具体某一实现的设计,越能提高代码的灵活性、扩展性、可维护性。

      总结一下,我们在做软件开发的时候,一定要有抽象意识、封装意识、接口意识。在定义接口的时候,不要暴露任何实现细节。

      接口的定义只表明做什么,而不是怎么做。
      而且,在设计接口的时候,我们要多思考一下,这样的接口设计是否足够通用,是否能够做到在替换具体的接口实现的时候,不需要任何接口定义的改动。

      补充:是否满足抽象意识判断:对外暴露的函数的话也是一样套上面的公式,如果是私有函数另说,不一定了

      是否满足封装意识判断:从使用者角度看,我会不会看到不该用的功能,能看到的功能是否满足上面两个特性?

      所以整体流程我感觉这三者应该是有顺序的,首先无脑接口/抽象类(接口),然后从调用者角度看哪些方法要暴露(封装),要暴露的方法名字是否满足抽象,即是否有暴露细节,会不会更改实现方法就需要改方法名(私有方法不算,可以有暴露实现细节,看个人吧也可以不暴露细节,大不了后面重构)

      • 接口意识:为实现类定义抽象的接口/抽象类
      • 抽象意识:在方法层面看就是函数的命名不能暴露任何实现细节。比如 uploadToAliyun() 就不符合要求,应该改为去掉 aliyun 这样的字眼,改为更加抽象的命名方式,比如:upload()。
      • 封装意识:封装具体的实现细节。根据前面抽象来看,抽象完之后不相关的方法都不应该让上层感知,比如,跟阿里云相关的特殊上传(或下载)流程不应该暴露给调用者。即不通用的不暴露,通用的再暴露出去
  • 是否需要为每个类定义接口?

    • 凡是都要有个“度”,过度使用这条原则,非得给每个类都定义接口,接口满天飞,也会导致不必要的开发负担。

    • 接口的目的:这条原则的设计初衷是,将接口和实现相分离,封装不稳定的实现,暴露稳定的接口。上游系统面向接口而非实现编程,不依赖不稳定的实现细节,这样当实现发生变化的时候,上游系统的代码基本上不需要做改动,以此来降低代码间的耦合性,提高代码的扩展性。

      当方法会有其他实现(这时候就已经说明未来很可能有其它实现了),或者不稳定的时候需要定义接口;
      1.不稳定的方法一般能事先确定,用接口能提高可维护性
      2.但在开发时往往不确定是否需要其他实现,我的原则是等到需要使用接口的时候再去实现。所以根据kiss原则一般我会先用方法实现,如果有一天真的需要有新的实现的时候再重构用接口

      个人感觉实在不确定,现阶段直接定义接口,就像写MVC一样。无脑接口,至少减少我们思考成本

      • 从这个设计初衷上来看,如果在我们的业务场景中,某个功能只有一种实现方式,未来也不可能被其他实现方式替换,那我们就没有必要为其设计接口,也没有必要基于接口编程,直接使用实现类就可以了。
      • 除此之外,越是不稳定的系统,我们越是要在代码的扩展性、维护性上下功夫。相反,如果某个系统特别稳定,在开发完之后,基本上不需要做维护,那我们就没有必要为其扩展性,投入不必要的开发时间。

理论七:为何说要多用组合少用继承?如何决定该用组合还是继承?

  1. 为什么不推荐使用继承?

    • 虽然继承有诸多作用,但继承层次过深、过复杂,也会影响到代码的可维护性。在这种情况下,我们应该尽量少用,甚至不用继承。
  2. 组合相比继承有哪些优势?

    • 继承主要有三个作用:表示 is-a 关系,支持多态特性,代码复用。而这三个作用都可以通过组合、接口、委托三个技术手段来达成。除此之外,利用组合还能解决层次过深、过复杂的继承关系影响代码可维护性的问题。
  3. 如何判断该用组合还是继承?

    • 灵活使用,看实际情况。如果类之间的继承结构稳定,层次比较浅,关系不复杂,我们就可以大胆地使用继承。反之,我们就尽量使用组合来替代继承。除此之外,还有一些设计模式、特殊的应用场景,会固定使用继承或者组合。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值