dljd_001_通过接口降低代码的耦合度(1)

  在学习jdbc之前我们首先来简单学习一下什么是面向接口编程?面向接口编程是怎么降低程序之间的耦合度的、使用面向接口编程给我们带来了那些好处?
一、需求

  比如说有这样一个需求、让我们用java程序来简单模拟一个人驾驶(启动和停止)一辆宝马车的。当大部分人看到这个需求之后就会觉得这是不是也太简单了、当然这大部分人设计出来的代码基本是如下的情况:

  1.1绝大部分人会有如下的实现:

  1.1.1设计人类  

package edu.aeon.driver;
/**
 * [说明]:人类
 * @author aeon
 */
public class Person {
    /**
     * 当一个类中以属性的方式引入其它类时、那么这种方式被称为聚合
     */
    private BMW bmw;
    public BMW getBmw() {
        return bmw;
    }

    public void setBmw(BMW bmw) {
        this.bmw = bmw;
    }
    /**
     * 驾驶
     */
    public void driver(){
        bmw.run();
        bmw.stop();
    }
}

  1.1.2设计宝马类

package edu.aeon.driver;
/**
 * [说明]:宝马类
 * @author aeon
 *
 */
public class BMW {
    /**
     * 宝马的启动
     */
    public void run(){
        System.out.println("启动宝马、行驶...");
    }
    /**
     * 宝马的停止
     */
    public void stop(){
        System.out.println("停止宝马!");
    }
}

  1.1.3测试类:

package edu.aeon.driver;
/**
 * [说明]:人驾驶宝马测试类
 * @author aeon
 */
public class TestDriver {

    public static void main(String[] args) {
        Person person=new Person();
        BMW bmw=new BMW();
        person.setBmw(bmw);
        person.driver();
    }
}

 1.1.4测试结果:

  

  我们可以看出来、这个需求是实现了、但是呢这样设计出来的程序是否合理呢?用合成和聚合(关于合成/聚合的含义详见本文档总结部分)关系实现人驾驶宝马是否合理呢?答案是no!

  2.1也有大部分会这么实现

    2.1.1设计人类

package edu.aeon.driver;
/**
 * [说明]:人类
 * @author aeon
 */
public class Person {
    /**
     * 驾驶
     * @param bmw 
     */
    public void driver(BMW bmw){
        bmw.run();
        bmw.stop();
    }
}

    2.1.2设计宝马类  

package edu.aeon.driver;
/**
 * [说明]:宝马类
 * @author aeon
 *
 */
public class BMW {
    /**
     * 宝马的启动
     */
    public void run(){
        System.out.println("启动宝马、行驶...");
    }
    /**
     * 宝马的停止
     */
    public void stop(){
        System.out.println("停止宝马!");
    }
}

  2.1.3测试类  

package edu.aeon.driver;
/**
 * [说明]:人驾驶宝马测试类
 * @author aeon
 */
public class TestDriver {

    public static void main(String[] args) {
        Person person=new Person();
        BMW bmw=new BMW();
        person.driver(bmw);
    }
}

  2.1.4测试结果

   

  显然我们看出第二种设计方法比较合理、但是这样设计出来的程序人类和宝马类严重的耦合在一起。当需求发生变化时(如:驾驶一辆奔驰/法拉利/大牛/p1)、我们又要去修改源码。那么怎么设计出来程序比较完美呢?请看第三种设计(面向接口设计/编程)。

  3.1极少部分人设计(非常有经验的人会这么设计)

    3.1.1设计人类  

package edu.aeon.driver;
/**
 * [说明]:人类
 * @author aeon
 */
public class Person {
    /**
     * 驾驶
     * @param car 注意此处:面向接口 
     */
    public void driver(Car car){  //注意
        car.run();
        car.stop();
    }
}

    3.1.2设计一个汽车接口

package edu.aeon.driver;
/**
 * 汽车接口
 * @author aeon
 */
public interface Car {
    void run();
    void stop();
}

    3.1.3设计宝马类

package edu.aeon.driver;
/**
 * [说明]:宝马类
 * @author aeon
 *
 */
public class BMW implements Car{
    /**
     * 宝马的启动
     */
    public void run(){
        System.out.println("启动宝马、行驶...");
    }
    /**
     * 宝马的停止
     */
    public void stop(){
        System.out.println("停止宝马!");
    }
}

    3.1.4测试类  

package edu.aeon.driver;
/**
 * [说明]:人驾驶宝马测试类
 * @author aeon
 */
public class TestDriver {

    public static void main(String[] args) {
        Person person=new Person();
        Car car=new BMW();
        person.driver(car);
    }
}

    3.1.5测试结果截图:

      

    

  那么这种情况可以说设计出来的程序完全符合java力荐的面向接口编程、此处也实现了多态、动态绑定、当需求发生变化时(比如我们现在要驾驶一辆法拉利)、只需要写个法拉利类实现Car这个接口并且重写其实现方法即可。如:  

package edu.aeon.driver;
/**
 * [说明]:法拉利类
 * @author aeon
 *
 */
public class Ferrari implements Car {
    /**
     * 法拉利的启动
     */
    @Override
    public void run() {
        System.out.println("启动法拉利、行驶...");

    }
    /**
     * 法拉利的停止
     */
    @Override
    public void stop() {
        System.out.println("停止法拉利!");
    }

}

Person类不用我们做任何的修改(解耦)。可见面向接口编程给我们带来的巨大便利。    

四、关于合成和聚合:

  1.合成和聚合关系有整体和局部的意义。比如人是一个整体、而这个人的心脏/胃/...是局部、这里的心脏/胃/...的人体器官是人的一部分。图例如下:

    

  人和心就是整体和局部的关系。人和车是吗?不是吧!

五、总结

  1.合成/聚合有整体和局部的关系。

  2.一个类成为另一个类的方法参数或者返回值、那么这种关系叫做依赖关系。这里显然人依赖于车才能驾驶、如果没有车那驾驶什么?但是程序中一定要依赖接口去实现。不然还是耦合在一起。

  3.以后我们设计到定义变量类型、方法的参数类型及返回值类型一律使用顶层接口方式。

如有任何疑问可联系邮箱: 给我发邮件、或直接联系QQ:1584875179 || 点返回首页

原文地址:https://www.cnblogs.com/aeon/p/10061981.html