Hefery 的个人网站

Hefery's Personal Website

Contact:hefery@126.com
  menu
73 文章
0 浏览
0 当前访客
ღゝ◡╹)ノ❤️

Java 编程思想的思考历程

首先是最基本的面向对象开始吧,Java 编程无时无刻不在用到对象,在 Java 的世界里万物皆对象,我们在用到对象前“必须”要创建这个对象才能使用。比如 Spring Framework 大部分时间都是在对象上做文章

最烂大街的办法就是直接 new 对象,同时也是最简单的方式。就相当于我是买生煎包的老板,客户要一个生煎包我就现做一个,要一个就再做一个。一个是从 JVM 的角度来看,这样操作也是很费内存的,同时频繁创建和销毁对象,触发内存回收机制也不是明智的选择,要是这样做生意,不是没赚到钱就是活活累死。从设计的角度思考,不优雅啊!new 是 Java 最基础的语法,体现不出编程水平的东西,当然了,new 一个对象的过程需要好好去探究探究,但不是现在要说的这事

为什么说 new 不好呢?那是因为 new 是实例化具体的类,如果要拓展,就必须要改动这里,new 变更的新类来替换,需求一变,代码就要频繁变更,这就造成了一种“不稳定”。先来理解这个变化,变化一般是用户点击或输入会造成变化,还有就是需求变更,这种变化就会要求系统也要做出相应的调整。稳定性是相对的,需要将变化隔离出来

接口、抽象类统一方法调用

这里要先说下设计模式里的开闭原则(OCP,Open Closed Principe),这些设计模式是前人不断实践和总结出适用于面向对象思想的好的思想。一般来说,我们编程都差不多也是要遵循这些设计模式去编码,其中最基本的原则就是开闭原则,类、函数、模块应该对拓展开放(对提供方),对修改关闭(对使用方),用抽象构建框架,用实现拓展细节,而不是通过修改原来的代码实现变化。不改原代码,做到兼容的效果,不过这个拓展还是得好好琢磨琢磨,curd 的 boy 笑了,再复制粘贴一份,改一改不就行了,当然也是一种可以解决问题的办法,倘若要增加几十份、几百份,那重复功能的代码可就要“爆炸”了,代码臃肿,功能单一,不优雅。

现在有个 Java 课程(JavaCourse),有名称(name)和价格(price)属性,但是后面课堂增加了别的课程,怎么办?再复制粘贴改成 Spring 课程、Python 课程吗?

刚刚说到了,其实问题就是重复功能的代码很多,那么把相同的功能抽象出来,弄成抽象类或者接口不就好了。到这,终于看到了使用编程思想去解决问题的一点光亮。接口、抽象类可以很好地统一方法调用,提炼出功能的共性,拓展类实现(接口)或继承(实现类)这些抽象出来的接口、抽象类

先有个大致思路:

image.png

Java 课程、Spring 课程、Python 课程都是“课程”,那么把“课程”提炼成一个接口 ICourse 对外提供 getName() 和 getPrice() 的获取方法,Java 课程(JavaCourse)就实现 ICourse 接口。

public interface ICourse {
    String getName();
    String getPrice();
}
public class JavaCourse implements ICourse {
    @Override
    public String getName() {
        return "Java Course";
    }

    @Override
    public String getPrice() {
        return "666";
    }
}
public class PythonCourse implements ICourse {
    @Override
    public String getName() {
        return "Python Course";
    }

    @Override
    public String getPrice() {
        return "999";
    }
}

这时再来个需求变更,Java 课程打折了,就会产生一个折扣价 discountPrice,怎么办?那就加一个 JavaDiscountCourse 类去继承 JavaCourse,继承了 JavaCourse 的原名称和原价格,但是这个是原价,不是折扣价。因为 JavaDiscountCourse 本来就是拓展的类,再增加一个获取原价的方法 getOriginalPrice()

public class JavaDiscountCourse extends JavaCourse {

    String price;  // 折扣价

    public String getOriginalPrice() {
        return super.getPrice();
    }
}

工厂模式分离对象实例化

看到这里,还没完,记得最早说的创建对象才是重点,JavaCourse、PythonCourse 是具体类,要使用它们还是得 new。所以兜兜转转是又回到起点?正如前面所述,接口、抽象类统一方法的调用,那么创建对象是否也可以统一起来。这就要说到设计模式的工厂模式了,引入工厂,把不稳定部分的 new,隔离出来

工厂模式有简单工厂、抽象工厂等,使用简单工厂做处理。创建工厂获取实例的方法 CourseFactory.getCourse(String courseName) ,但在 CourseFactory.getCourse 还是通过 courseName 要 new 具体的课程,也还只是把变化隔离到了 CourseFactory 工厂类中,这个时候可以运用反射的机制消除 new。

反射可以通过 Class 创建对象

Class<?> cla = Class.forName(courseName);
Course course = (Course)cla.newInstance();

IoC和DI管理对象

系统依靠各种对象相互之间协作维持运行,随着时间推移,系统也会时不时增加新功能,对象随之增多,对象与对象之间的依赖增加,无形中增强了系统各个组件的耦合。放到中大型的系统无疑是要人命的,你想想,你仔细想想,就算是一个中型的项目,要你改动某个功能,是不是还要考虑改动的地方、改动的对象会影响系统其他的功能和业务,这个改动是十分繁琐的事情,也行改要不了多久,但是找,可能需要花费数倍时间,除非你对系统是很了解的,可以一下子就定位到需要调整的各个位置。

IoC的出现,就为这个问题带来了新的思路。其实说到底现在这玩意耦合程度会随系统功能增加而越来越严重,所以 IoC 一个主要作用就是解耦。那么 IoC 是什么,又是怎样去解耦的呢?

最后在说 IoC,先来看看它是如何解耦的。各个对象将并不直接联系,而是通过 IoC 容器去使用其他对象。引入第三方 IoC 容器,使得 A、B、C、D 没有耦合的部分,改动 A 时就不用担心会影响到其他对象。如图,现在 A、B、C、D 齿轮的转动全依靠 IoC 去带动,而非之前那样四个小齿轮紧密耦合在一起。

image.png

IoC,Inversion of Control,控制反转,这个词就很有意思了,把控制权反过来了,那么原来控制权在谁手上,用了 IoC 又反转给了谁?

没有 IoC 时,A 获取 B 是主动获取;引入 IoC 后,A 获取 B 是通过 IoC 去获取。获取 B 的控制权由 A 转到了 IoC 手上

DI,Dependency Injection,依赖注入,当 A 需要使用 B 时,就把 A 所依赖的 B 注入到 IoC,虽然也说的是“控制反转”的意思,但是很多时候是认为 DI 是 IoC 的实现之一。


标题:Java 编程思想的思考历程
作者:Hefery
地址:http://hefery.icu/articles/2022/10/25/1666668879673.html