Bootstrap

5年java经验对java四大特性的理解和感悟

java 四大特性

  • 面向对象三大特性: 封装, 继承, 多态
  • java四大特性: 封装, 继承, 抽象, 多态

抽象

抽象这个范围很广, 整个编程界甚至编程界之外皆有抽象的特征.

java是面向对象的语言, 在面向对象基础上又增加了一个抽象特性, 简单来说就是通过增加 抽象类接口 使得抽象这个概念在java语言里面具象化.

抽象和继承, 封装紧密联系, 甚至和多态也分不开,

它比继承和多态稍微困难点, 但是有经验的开发者, 对抽象的使用也是相当稳定的.

依赖倒置原则: 简单来说, 就是面向接口编程, 面向抽象编程, 面向契约编程, 使用依赖倒置原则和抽象结合起来非常合适.

个人理解: 依赖倒置原则简单来说就是一个高内聚.

低层抽象引出高层抽象, 但不该限制高层抽象, 应从高层抽象角度重新去定义低层抽象, 实现高聚合: 底层抽象依赖高层抽象, 而不是高层抽象依赖底层抽象.

个人的理解: 我们在使用一个事物的时候会将其抽象化成一类事物, 再形成一种模式, 再逐渐的形成一种思想. 形成思想后, 我们就应该抛弃原来的具象化的模式, 从思想的角度去对模式去进行重新定义.

继承

继承有很多优点, 但是继承使用不当, 会造成耦合和复杂度高.

里氏转换简直就是专门为继承定制的法则, 里氏转换可以是我们能够在使用继承优点的前提下, 规避其缺点.

里氏转换来规约继承

  1. 避免子类有自己的个性, 一旦子类有了自己独有的个性, 那么父子类关系就难以调和, 违背里氏转换.
    最直观的场景就是, 我明明以为是这样执行的, 怎么偏偏那样执行.

  2. 避免重写方法, 尽量重写抽象
    简单来说, 就是无论一个父类里面有多少子类, 整个方法继承链里面真正被实现的方法只应该有一个(重写Object里面的几个方法不算).

    • 子类只应该实现父类的抽象方法, 不应该实现成员方法.
    • 父类和子类的方法应该只有一个个性, 至少在同一个模块中, 父类想让子类实现方法, 就应该将方法设计为抽象方法, 那么子类就应该去实现这个抽象方法.
  3. 对于封装模块, 或者是调用模块来说,
    对于封装的模块, 如实现了一个框架, 打成了一个jar, 可以封装一个默认通用的方法方便别人使用, 但是对于封装的模块来说, 也应该保证避免重写方法, 尽量重写抽象.
    对于使用封装的jar或框架的场景, 可以通过实现别人已经实现的方法, 使得业务满足自己的逻辑, 但是最多只能重写一次.

一旦子类多次实现父类方法, 那么关系就变得复杂.

继承使用不当, 虽然容易造成各种耦合性问题, 但是有上面三点为其把门, 一般来说只要照着规矩来, 也不会出现什么问题.

多态

多态三要素

  1. 继承
  2. 重写
  3. 父类引用指向子类对象

重载不应该是多态里面的, 顶多算是个语法糖

多态实现方式

  1. 重写
  2. 接口
  3. 抽象类和抽象方法

多态优点

  1. 可替换
  2. 可扩充
  3. 抽象和接口性.
  4. 简化开发

多态没有专用的设计原则, 它一个非常大的好处就是简化开发, 在java里面, 很多设计模式都是依照其进行完成的.

涉及模式

  1. 策略(简直是多态的亲儿子)
  2. 访问者
  3. 桥接

评论设计模式的时候, 总是有人会将策略模式和各种乱七八糟的模式进行对比, 就是因为策略模式是用最简单的多态实现的. 而其它设计模式也是用多态实现的, 所以导致拿策略模式做各种对比.

关于java里面多态的理解, 把java的继承链搞明白就差不多了.

封装

新手觉得最简单的是封装, 高手觉得最难的是封装, 封装是最基本的面向对象特性, 也是最难掌握的.

不像抽象和继承, 只要照着大致不变的思维去做就行了, 依赖倒置和里氏转换, 可以让抽象和继承变得相当六, 一般情况下不会出现各种问题.

封装优点

  1. 良好的封装能够减少耦合。
  2. 类内部的结构可以自由修改。
  3. 可以对成员变量进行更精确的控制。
  4. 隐藏信息,实现细节。

但是封装封不好, 直接会引起各种问题, 而且封装也不是说随随便便就可以很好地设计的.

  1. 涉及模式

    • 接口隔离: 这个应该在封装里面.
    • 单一性职责: 只做一件事情
    • 迪米特法则(最少知道原则): 尽量少往外暴漏自己.

    3个法则, 都无法为封装保驾护航, 实际上除此之外还有很多设计方法能够帮到封装.

  2. 封装封不好弊端

    • 调用困难, 但是继承和抽象, 解决或者是预防问题不大.
    • 更改困难, 这才是最恶心的, 一般来说系统都会各种改动, 业务逻辑可能一变再变, 抽象和继承都可以一次做的比较完美, 但是封装很难一次性做好.
  3. 实体封装

    • 数据库设计, 实际上数据库设计就是实体的封装, 若是数据库设计不好, …后面具头疼.
    • 实体设计: 数据实体和业务实体的设计, 做不好就容易造成各路畸形和调用困难.

    当然为了解决这个问题, 可以通过DO, BO, DTO, AO 等分离层级, 使得数据库实体不会太过影响

  4. 计算功能性设计

    最难的就是 C/S 段计算功能性设计, 甚至说很多人意识不到封装有多么重要, 就是因为没有做过C/S端开发或者是功能性开发.

    此处不是像数据库一样, 只有实体属性, 功能性开发里面还有各种方法, 各种算法糅合在一起.

    我开发过好多功能, 也做个好几个java swing应用, 封装封不好会导致后续持续开发困难.

    一般做完APP之后, 对代码进行调整优化的时候, 最终发现与其说是在优化各种逻辑, 不如说就是在优化各种封装, 而且巨浪费时间.


封装是最难最耗时间的, 也是最简单的"最不容易出错的"(打个引号).

开发的时候, 封装设计的再垃圾, 代码都可以正常运行, 但是随着继续开发, 垃圾封装带来的弊端会越来越大.

过个几个月, 开发人员自己都不认识自己的代码, 也越来越难开发, 越来越难维护.

但是就像是在建大楼一样, 撒点泥巴, 放上砖头, 就可以把下面几层楼盖起来, 但是大型的项目是盖摩天大楼, 这种垃圾封装能改多少层呢?

领导看不到, 程序员不想管(甚至也看不到), 垃圾封装持续正常的运行, 程序员正常的开发, 业务正常的下发.

最终项目代码的畸形, 屎山的堆积, 卡到一定地步死活起不来, 卡爆摩天楼.

;