抽象类和接口(含面向对象六大设计原则)

面向对象六大设计原则

1.单一职责原则 (Single Responsibility Principle)

单一职责原则,简称SRP,定义是应该有且仅有一个类引起类的变更,即:一个类只负责一个职责。

优点:

    类的复杂性降低,实现什么职责都有明确的定义;
    逻辑变得简单,类的可读性提高了,而且,因为逻辑简单,代码的可维护性也提高了;
    变更的风险降低,因为只会在单一的类中的修改。


2.里氏替换原则 (Liskov Substitution Principle)

单一职责原则,简称LSP。定义如下:

    复杂定义:如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有对象o1都替换成o2的时候,程序P的行为都没有发生变化,那么类型T2是类型T1的子类型。

    简单定义:所有引用基类的地方必须能透明地使用其子类的对象。

通俗地讲,就是:子类可以扩展父类的功能,但不能改变父类原有的功能。

面向对象的三大特征是封装、继承和多态。其中的继承,当子类继承父类时,虽然可以复用父类的代码,但是父类的属性和方法对子类都是透明的,子类可以随意修改父类的成员。若需求变更,子类对父类的方法进行了一些复写的时候,其他的子类可能就需要随之改变,这在一定程度上就违反了封装的原则,解决的方案就是引入里氏替换原则。

里氏替换原则为良好的继承定义了一个规范,它包含了4层含义:

    子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法。
    子类可以有自己的个性,可以有自己的属性和方法。
    子类覆盖或重载父类的方法时输入参数可以被放大。
    子类覆盖或重载父类的方法时输出结果可以被缩小,也就是说返回值要小于或等于父类的方法返回值。


3.依赖倒置原则 (Dependence Inversion Principle)

依赖倒置原则,简称DIP,定义是:

    高层模块不应该依赖底层模块,两者都应该依赖其抽象;

    抽象不应该依赖细节;

    细节应该依赖抽象。

不可分割的原子逻辑就是底层模块,原子逻辑的再组装就是高层模块。
在Java中,抽象是指接口或抽象类,两者都不能被实例化;而细节是实现接口或继承抽象类产生的类,也就是可以被实例化的实现类。依赖倒置原则是指模块间的依赖是通过抽象来发生的,实现类之间不发生直接的依赖关系,其依赖关系是通过接口是来实现的,这就是俗称的面向接口编程。所以说依赖倒置原则的核心就是要我们面向接口编程,理解了面向接口编程,也就理解了依赖倒置。


4.接口隔离原则 (Interface Segregation Principle)

接口隔离原则,简称ISP,定义是:

    客户端不应该依赖它不需要的接口

也就是说客户端需要什么接口就提供什么接口,把不需要的接口剔除掉,这就需要对接口进行细化,保证接口的纯洁性。换成另一种说法就是,类间的依赖关系应该建立在最小的接口上,也就是建立单一的接口。

建立单一接口,这里需要和单一职责区分。单一职责原则要求的是类和接口职责单一,注重的是职责,一个职责的接口是可以有多个方法的,而接口隔离原则要求的是接口的方法尽量少,模块尽量单一,如果需要提供给客户端很多的模块,那么就要相应的定义多个接口,不要把所有的模块功能都定义在一个接口中,那样会显得很臃肿。


5.迪米特原则 (Law of Demeter)

迪米特原则,简称LoD,也被称为最少知识原则,它描述的规则是:

    一个对象应该对其他对象有最少的了解

也就是说,一个类应该对自己需要耦合或调用的类知道的最少,类与类之间的关系越密切,耦合度越大,那么类的变化对其耦合的类的影响也会越大,这也是我们面向设计的核心原则:低耦合,高内聚。

迪米特法则还有一个解释:只与直接的朋友通信。

什么是直接的朋友呢?每个对象都必然与其他对象有耦合关系,两个对象的耦合就成为朋友关系,这种关系的类型很多,例如组合、聚合、依赖等。其中,我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出现在局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部。


6.开闭原则  (Open Closed Principle)

开闭原则,简称OCP,是Java世界里最基础的设计原则。定义是:     

    一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。


简而言之,在编程过程中,需求会不断变化,我们的软件实体应该通过扩展来方式来实现变化,而不是通过修改已有的代码实现变化。所以,我们的程序需要有易于扩展、易于维护、易于升级等特性。
遵循开闭原则的最好手段是抽象,用抽象构建框架,用实现扩展细节。因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节,我们用从抽象派生的实现类来进行扩展,当软件需要发生变化时,我们只需要根据需求重新派生一个实现类来扩展就可以了。当然前提是我们的抽象要合理,要对需求的变更有前瞻性和预见性才行。但从开闭原则的角度说,更好的方式是面向接口编程,这样可以更好的扩展性,同时也可降低耦合,可提高系统的稳定性。

————————————————
版权声明:本文为CSDN博主「樱花语」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zyy_hbcz/article/details/104909965

程序场景

模拟一个生活场景:员工乘坐交通工具(自行车、公交车、地铁)回家。

 

抽象类的基本概念

  • 抽象思维,是人类思维达到高级阶段产生的一种能力,例如,当小孩子思维尚未成熟时,他们只能掌握具体概念,他们在学习代词“你、我、他”时往往遇到困难,因为代词具有较高的抽象性。
  • 抽象类就是为了继承而存在的,如果你定义了一个抽象类,却不去继承它,那么等于白白创建了这个抽象类,因为你不能用它来做任何事情。
  • 对于一个父类,如果它的某个方法在父类中实现出来没有任何意义,必须根据子类的实际需求来进行不同的实现,那么就可以将这个方法声明为abstract方法,此时这个类也就成为abstract类了。

抽象类

抽象类的定义语法:访问修饰符 abstract class ClassName {   }


抽象类和普通类的区别
抽象类要用abstract修饰
普通类可以实例化,抽象类不能实例化



如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。

抽象方法

 访问修饰符 abstract class ClassName {  
     访问修饰符 abstract 返回值类型  方法名(参数列表…);
   }


抽象方法和普通方法的区别
普通方法必须要有方法体,抽象方法不能有方法体(大括号也没有)
抽象方法要用abstract修饰
抽象方法必须存在于抽象类中

抽象类和抽象方法

抽象类与抽象方法的使用
抽象类中可以没有抽象方法,但包含了抽象方法的类必须被定义为抽象类
如果子类没有实现父类的所有抽象方法,子类必须被定义为抽象类
没有抽象构造方法,也没有抽象静态方法
抽象类中可以有非抽象的构造方法,创建子类的实例时可以调用

员工乘坐交通工具回家案例:

生活中的接口

在生活中,接口是一套规范,只要是满足这个规范的设备,就可以将它们组装在一起,从而实现该设备的功能。

 

接口

在软件中,接口同样是一种规范或标准,它们可以约束类的行为,是一些方法特征的集合,但是没有方法的实现。


定义接口的语法:
[访问修饰符]  interface 接口名   extends 父接口1,父接口2,…{
                    //常量定义
                    //方法定义
}


类实现接口的语法:
[访问修饰符]  class  类名  extends  父类名 implements  接口1,接口2,…{
                    //类成员
}

接口的特性

  • 接口的命名规则与类相同。如果修饰符是public,则该接口在整个项目中可见;如果省略修饰符,则该接口只在当前包可见。
  • 接口中可以定义常量,不能定义变量。接口中的属性都会自动用public static final 修饰,即接口中的属性都是全局静态常量。
  • 接口中方法自动用public  abstract修饰,接口中所有方法都是抽象方法。
  • 接口不能实例化,接口中不能有构造方法。
  • 接口直接可以通过extends实现继承关系,一个接口可以继承多个接口,但是接口不能继承类。
  • 接口的实现类必须实现接口的全部方法,否则必须定义为抽象类。

USB接口案例

接口表示一种能力

“做这项工作需要一个木匠”

木匠并不是指某一个人,而代表一种能力,招聘木匠就是招聘具备该能力的人

接口表示一种能力

体现在接口的方法上,一个类实现了某个接口,就表示这个类具备了某种能力

接口表示一种约定

生活中,我们使用的两相电源插座,规定了
两个接头间的额定电压
两个接头间的距离
接头的形状


接口表示一种约定

有些接口只有名称

程序场景

问题:要求实现打印机打印功能。打印机的墨盒可能是彩色的,也可能是黑白的,所用的纸张可以有多种类型,如A4、B5等,并且墨盒和纸张都不是打印机厂商提供的。
打印机厂商如何避免自己的打印机与市场上的墨盒、纸张不符呢?

 

使用接口实现打印机打印功能

思路分析
制定墨盒、纸张的约定或标准
其他厂商按照墨盒、纸张的标准生产墨盒、纸张
然后打印机厂商按照约定对墨盒、纸张开发打印机,无论最后使用的是哪个厂商提供的墨盒或纸张,只要符合统一的约定,打印机都可以打印。

 

面向接口编程

面向接口编程就是先把客户的业务逻辑线提取出来,作为接口,业务具体实现通过该接口的实现类来完成。当客户需求变化时,只需编写该业务逻辑的新的实现类,替换该接口的实现类就可以完成需求,不需要改写现有代码,减少对系统的影响。

面向接口编程的优点

接口体现了约定和实现相分离的原则
面向接口编程就意味着:开发系统时,主体架构使用接口,接口构成系统的骨架,这样就可以通过更换实现接口的类来实现更换需求。


面向接口编程的优点:

  1. 降低代码间的耦合性
  2. 易于程序的扩展,提高了程序的可扩性性
  3. 提高了程序的可维护性

面试题

抽象类和接口的联系和区别?

相同点:
代表系统的抽象层
都不能被实例化
都能包含抽象方法:用于描述系统提供的服务,不必提供具体实现

不同点:
在抽象类中可以为部分方法提供默认实现,而接口中只能包含抽象方法
抽象类便于复用,接口便于代码维护
一个类只能继承一个直接的父类,但可以实现多个接口

总结

 

 

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值