zoukankan      html  css  js  c++  java
  • 由Java中List和ArrayList 引发的思考,什么是面向接口编程?

    一、已经知道的内容如下:

    1. 什么是构造函数?
      • Java 构造函数,也叫构造方法,是Java 类中的一种特殊方法,方法名与类名相同,一般用来初始化成员变量,当要生成一个类的对象(实例)的时候就会调用构造函数,如果类中没有显示声明类的构造方法,Java 会自动生成一个默认的不带参数的空构造函数。(接口类和抽象类没有构造函数)
    2. 什么是接口?
    • 接口是功能的集合,同样可以看做是一种数据类型,是一种特殊的抽象类。接口中的方法也全部都是抽象的,直接new 接口来调用是没有意义的,Java 也不允许这样。当然接口也可以被实现,实现接口的类需要重写接口中的方法,并完成具体的逻辑(是否体现多态?)
    • 接口中成员的特点:
      • 接口中定义变量,但变量必须有固定的修饰符修饰--public static final,所以接口中的变量也称为常量(需要和enmu做对比),其值不能改变
      • 接口中定义方法 ,同样也有固定的修饰符--public abstract
      • 接口不能创建对象
      • 子类必须覆盖接口中所有抽象方法(实现接口方法),才可以实例化,子类也可以有自己的方法,但是通过接口指向创建的实例不能调用子类的方法,这也是多态的缺点,无法直接访问子类特有的成员及方法
    • 接口的思想:方便后期维护,只需要关心接口中的方法即可。集合体系中大量使用了接口
    • 接口的优点:①类与接口的关系,实现关系,而且是多实现,打破了一个类只能继承一个父类的限制;②对外提供规则③降低了程序的耦合性(可以实现模块化开发,每个人实现自己的模块,提高开发效率)
    • 接口和抽象类的区别:详见笔记 深入理解abstract class和interface
     

    二、回到正题来

    1. 面向接口编程
    List 是一个接口,而接口不能实例化(没有构造函数),而ArrayList是List 接口的一个实现类。 我们可以像下面那样为List接口创建一个指向自己的对象引用,而ArrayList实现类的实例对象就在这充当了这个指向List接口的对象引用。
    List<String> list = new ArrayList<String>();(JDK1.7 ArrayList 容量及容量扩充:初始0,添加一个Object之后为10,每次扩充为(原始容量*3/2)和(数组的长度+1)之间的较大值)
    引出:这是一个面向接口编程的简单例子,也是面向对象的重要知识点。
    我们在学习OOP 的时候,提出面向对象最重要的就是多态(方法重载和方法覆盖),我们都知道接口和抽象不能被实例化,但是他们可以创建一个指向自己的对象引用(为什么要指向自己,就是为了实现接口编程),他们的实现类或者子类就在充当这样的角色,这也是面向对象编程中多态的优势(不严谨,因为接口和多态的本质不在一个层级上,多态是面向对象的特征之一,而接口是一系列方法的声明,接口可以体现多态性,但是多态不一定就要用接口,简而言之,你可以再程序里用代码定义一个接口,多态只是对代码特征的一种描述,一种概念上的抽象和总结)。
    1. Spring IoC 的原理概述

    通过上面的例子分析,我们不难发现。List 的实现类有很多(ArrayList、LinkedList 等),我们可以根据需求进行选择合适的实现类,灵活运用,这也采用面向接口的一大优势,降低代码耦合度(只需要改变指向List 的接口,而不需要改变List 的实现类 )。再看,在日常开发中我们经常会遇到这种情况:

    public class BookServiceImpl {
        private BookDaoImpl bookDaoImpl;
    
        public void oldCode() {
            // 原来的做法
            bookDaoImpl = new BookDaoImpl();
            bookDaoImpl.getAllCategories();
        }
    }
    //----------------new---------------------
    public class BookServiceImpl {
        // interface
        private BookDao bookDao;
    
        public void newCode() {
            // 变为面向接口编程
            bookDao = new BookDaoImpl();
            bookDao.getAllCategories();
        }
    }
    

    BookServiceImpl类中由原来直接与BookDaoImp打交互变为BookDao,即使BookDao最终实现依然是BookDaoImp,这样的做的好处是显而易见的,所有调用都通过接口bookDao来完成,而接口的真正的实现者和最终的执行者就是bookDaoImpl,当替换bookDaoImpl类,也只需修改bookDao指向新的实现类。

    虽然上述的代码在很大程度上降低了代码的耦合度,但是代码依旧存在入侵性和一定程度的耦合性,比如在修改bookDao的实现类时,仍然需求修改BookServiceImpl的内部代码,当依赖的类多起来时,查找和修改的过程也会显得相当糟糕,因此我们仍需要寻找一种方式,它可以令开发者在无需触及BookServiceImpl内容代码的情况下实现修改bookDao的实现类,以便达到最低的耦合度和最少入侵的目的。实际上存在一种称为反射的编程技术可以协助解决上述问题,反射是一种根据给出的完整类名(字符串方式)来动态地生成对象,这种编程方式可以让对象在生成时才决定到底是哪一种对象,因此可以这样假设,在某个配置文件,该文件已写好bookDaoImpl类的完全限定名称,通过读取该文件而获取到bookDao的真正实现类完全限定名称,然后通过反射技术在运行时动态生成该类,最终赋值给bookDao接口,也就解决了刚才的存在问题,这里为简单演示,使用properties文件作为配置文件,className.properties如下:

    bookDao.name=com.zejian.spring.dao.BookDaoImpl
    

    获取该配置文件信息动态为bookDao生成实现类:

    public class BookServiceImpl implements BookService {
        // 读取配置文件的工具类
        PropertiesUtil propertiesUtil = new PropertiesUtil("conf/className.properties");
    
        private BookDao bookDao;
    
        public void DaymicObject() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
            // 获取完全限定名称
            String className = propertiesUtil.get("bookDao.name");
            // 通过反射
            Class c = Class.forName(className);
            // 动态生成实例对象
            bookDao = (BookDao) c.newInstance();
        }
    }
    

    的确如我们所愿生成了bookDao的实例,这样做的好处是在替换bookDao实现类的情况只需修改配置文件的内容而无需触及BookServiceImpl的内部代码,从而把代码修改的过程转到配置文件中,相当于BookServiceImpl及其内部的bookDao通过配置文件与bookDao的实现类进行关联,这样BookServiceImpl与bookDao的实现类间也就实现了解耦合,当然BookServiceImpl类中存在着BookDao对象是无法避免的,毕竟这是协同工作的基础,我们只能最大程度去解耦合。

    了解了上述的问题再来理解IOC就显得简单多了。Spring IOC 也是一个java对象,在某些特定的时间被创建后,可以进行对其他对象的控制,包括初始化、创建、销毁等。简单地理解,在上述过程中,我们通过配置文件配置了BookDaoImpl实现类的完全限定名称,然后利用反射在运行时为BookDao创建实际实现类,包括BookServiceImpl的创建,Spring的IOC容器都会帮我们完成,而我们唯一要做的就是把需要创建的类和其他类依赖的类以配置文件的方式告诉IOC容器需要创建那些类和注入哪些类即可。Spring通过这种控制反转(IoC)的设计模式促进了松耦合,这种方式使一个对象依赖其它对象时会通过被动的方式传送进来(如BookServiceImpl被创建时,其依赖的BookDao的实现类也会同时被注入BookServiceImpl中),而不是通过手动创建这些类。我们可以把IoC模式看做是工厂模式的升华,可以把IoC看作是一个大工厂,只不过这个大工厂里要生成的对象都是在配置文件(XML)中给出定义的,然后利用Java的反射技术,根据XML中给出的类名生成相应的对象。从某种程度上来说,IoC相当于把在工厂方法里通过硬编码创建对象的代码,改变为由XML文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性,更是达到最低的耦合度,因此我们要明白所谓为的IOC就将对象的创建权,交由Spring完成,从此解放手动创建对象的过程,同时让类与类间的关系到达最低耦合度。

    注:以上第二条参考博文 关于Spring IOC (DI-依赖注入)你需要知道的一切

     
     
    版权声明:本文为博主原创文章,未经博主允许不得转载。 
  • 相关阅读:
    20145109 《Java实验报告1》
    20145109 《Java程序设计》第五周学习总结
    20145109 《Java程序设计》第四周学习总结
    20145109 《Java程序设计》第三周学习总结
    20145109《Java程序设计》第二周学习总结
    20165322 第十周课下补做
    20165322 实验三 敏捷开发与XP实践
    20165322 第九周学习总结
    20165322 第二周结队编程-四则运算
    20165322 第八周学习总结
  • 原文地址:https://www.cnblogs.com/hellovoyager1/p/9143868.html
Copyright © 2011-2022 走看看