Java为什么要面向接口编程

就我目前的水平来看,Java使用面向接口编程主要有3点好处。

  • 代码的灵活性和高可复用性
  • 良好的可扩展性
  • 低耦合

   我们学习知识,要做到知其然而知所以然,知道一些弊端,你才能更好的体会到使用该技术所来的好处,印象才能更加深刻。

一、代码的灵活性和高可复用性

例如,我现在有这一需求,有很多类型的手机,持有者需要使用它们打电话。

我们先看看不使用接口编程,对程序的影响是什么。

package interfaceoriented;

public class Huawei {
    public void call () {
        System.out.println(getClass().getSimpleName() + " call");
    }
}

public class Vivo {
    public void call() {
        System.out.println(getClass().getSimpleName());
    }
}

public class Mi {
    public void call() {
        System.out.println(getClass().getSimpleName());
    }
}

public class Iphone{
    public void call() {
        System.out.println(getClass().getSimpleName() + " call");
    }
}

public class Holder {
    public void call(Huawei huawei) {
        huawei.call();
    }
    public static void main(String[] args) {
        new Holder().call(new Huawei());
    }
}

   我现在定义了4款手机Huawei、Vivo、Mi 和 Iphone ,我们使用某一特定类作为方法call()的参数,Holder只能使用Huawei手机call。如果Holder想使用其他手机call,该怎么办呢?

   试试使用继承机制。Huawei、Vivo、Mi都继承自共同的父类Android,Iphone继承自父类Ios。在这里你可能会有疑问,为什么它们不继承同一个父类。我的设计初衷是这样的,每款手机都有操作系统,Holder有一些方法需要识别每款手机的操作系统,这就跟我们现实生活中经常会比较手机的操作系统一样。所以我将有关操作系统的信息放在父类中,子类不需要重写父类的方法,只需继承父类就能拥有操作系统的信息。通过这种设计,代码的复用性就会高很多了。

package interfaceoriented;

public class Android {
    void call() {}
    void system() {
    System.out.println("Android Operating System");
    }
}

public class Ios {
    void call() {}
    void system() {
        System.out.println("IOS Operating System");
    }
}

public class Huawei extends Android{
    public void call () {
        System.out.println(getClass().getSimpleName() + " call");
    }
}

public class Vivo extends Android{
    public void call() {
        System.out.println(getClass().getSimpleName() + " call");
    }
}

public class Mi extends Android{
    public void call() {
        System.out.println(getClass().getSimpleName() + " call");
    }
}

public class Iphone extends Ios{
    public void call() {
        System.out.println(getClass().getSimpleName() + " call");
    }
}


public class Holder {
    public void call(Android android) {
        android.call();
    }
    public static void main(String[] args) {
        Holder h = new Holder();
        // 使用华为手机call
        h.call(new Huawei());
        // 使用Vivo手机call
        h.call(new Vivo());
        // 使用Mi手机call
        h.call(new Mi());
    }
}

   通过使用父类Android作为方法参数,Holder可以使用任何继承自Android的手机call,或任何继承自Ios的手机call。

  这回Holder希望既能使用Android类型的手机call,又能使用Ios类型的手机call,又或者说只要是手机,无论什么操作系统,无论什么型号,我都能call。这怎么办呢?

定义一个接口Mobile, Android和Ios都实现此接口。

package interfaceoriented;

public interface Mobile {
    void call();
}

public class Android implements Mobile{
    public void call() {}
    void system() {
        System.out.println("Android Operating System");
    }
}

public class Ios implements Mobile{
    public void call() {}
    void system() {
        System.out.println("IOS Operating System");
    }
}


public class Holder {
    public void call(Mobile mobile) {
        mobile.call();
    }
    public static void main(String[] args) {
        Holder h = new Holder();
        // 使用iphone
        h.call(new Iphone());
        // 使用Huawei
        h.call(new Huawei());
    }
}

  通过使用接口类型作为方法参数,Holder可以使用任何类型的手机call,且方法实现细节不用任何改变。通过使用接口类型,方法参数的具体类型变得越来越模糊,也即是“类型”范围越广,接受的参数类型越多,方法的表现形式就越多。所以通过这种方式定义的方法灵活度更高、复用性更强。这就是我们为什么使用面向接口编程的原因之一。

  关于代码的灵活性。我的理解是:某个类或某个方法,根据外面环境的改变(传递给类的持有对象或传递给方法的参数的改变),这个类或方法能够随之产生不同的表现形式,这种类或方法就具有非常好的灵活性。

二、良好的可扩展性

什么是程序的可扩展性?

  实际工作中,在已经开发好的系统上,新增加了功能,我们只需编写新功能的代码,而不需要改变原来的代码。新增的代码能够很好的和原来的代码整合。这种系统,我们称之为有良好的可扩展性。

  例如:现在又出了新的操作系统(名为Steve)的一系列手机,Holder想使用这一系列的手机,那该怎么办呢?前面我们已经提到过,使用特定类型或继承体系作为方法的形式参数的弊端。既然已经定义了接口,我们只需实现这个接口来创建新操作系统的一系列手机就可以了。

package interfaceoriented;

public class Steve implements Mobile {
    public void call() {}
    public void system() {
        System.out.println("Steve Operating System");
    }
}

public class StevePhone1 extends Steve {
    public void call() {
        System.out.println(getClass().getName() + " call");
    }
}

public class StevePhone2 extends Steve {
    public void call() {
        System.out.println(getClass().getName() + " call");
    }
}

public class Holder {
    public void call(Mobile mobile) {
        mobile.call();
    }
    public static void main(String[] args) {
        Holder h = new Holder();
        h.call(new StevePhone1());
        h.call(new StevePhone2());
    }
}

  看到了吗? Holder的call()方法没有任何修改,只需实现Mobile接口,无论以后还会新出什么类型的手机,Holder都能使用。这就是接口给程序带来的可扩展性。

3. 低耦合度

什么是程序的耦合度?

  以前一直对程序的耦合度有一种误解:认为一个对象改变,会影响另一个对象的状态。那时就非常疑惑不解:某一大的功能模块需要很多其他小的功能模块提供支持,而实现一个小的功能模块又需要多个方法之间相互调度运行。这怎么降低耦合度,难道设计一个方法,不调用其他方法的运算作为参数,而是所有计算都在一个方法中实现?那这方法也太臃肿且杂乱了,而且也不符合面向对象的设计原则——单一责任原则。那耦合度到底什么呢?下面说说我的理解。

  耦合度是指代码之间的依赖程度。当修改某个类或某个方法的代码时,尽量不用去修改其他类或方法的代码,所修改的其他类或方法的代码越少,程序的耦合性就越低。

  在回头看看讲解可扩展性的例子,我们新增加了功能,新增加了一些类,但Holder类的call()并没有任何改变。随便你们怎么折腾,只要你们实现了接口,我都能接受,不会做出任何改变。

  这就降低了程序的耦合度,其他地方修改,而我却不需要修改(任你千变万化,我自岿然不动)。

  • 5
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值