编码灵魂(5)-接口隔离原则

本文探讨编码的灵魂,重点关注设计模式中的接口隔离原则(ISP)。通过解释接口和抽象类的区别,指出接口在多继承中的灵活性。作者指出,ISP强调接口应具有单一功能,避免实现者承担不必要的方法。文章通过运动类接口的反例,展示了如何根据ISP拆分接口,提高代码的优雅性和可维护性。
摘要由CSDN通过智能技术生成

引言

我觉得编码是有灵魂的,就像每个人都有信仰一样。那么如何去体现信仰,如何凸显灵魂就需要依赖它所固有的原则。最近学习了设计模式的六大原则,有所感悟,特此做总结和记录。在本篇博文中详细介绍了接口隔离原则(ISP)的概念,同时用几个简单的例子举例说明。同时,在开头我会在技术点模块中,说一些不太相关的东西,作为拓展,希望对大家有所帮助。笔者目前整理的一些blog针对面试都是超高频出现的。大家可以点击链接:http://blog.csdn.net/u012403290

今天我们说要介绍的原则主要是针对接口的,所以在这之前,我们大致了解一下接口:
技术点
1、接口和抽象类
两种定义多个实现的类型,两者都是建立在抽象的描述之上。最大的区别在于:抽象类可以包含某些方法的具体实现,但是接口不允许。在博主看来,两者是各有所长的,在java的单继承概念中,只能实现一个抽象类,但是可以实现很多的接口,所以在这个程度上来说,接口会更加灵活。但是,在有些情况下,比如说接口需要提供一个新的方法,那么它所有的实现都必须去对于这个新的方法进行实现,“牵一发而动全身”。但是如果是抽象类的话,那么可以在抽象类中直接实现该方法,不需要去修改抽象类的实现,这个时候抽象类就显得比较优越。在这里,我想起很有意思的一个技术点,叫“骨架实现”,经常研读JDK源码的小伙伴,肯定会有所领悟的,比如说HashMap(实现类)是继承了AbstractMap(抽象类)的,而且AbstractMap(抽象类)是作为Map(接口)的一个短小实现,在这个过程中AbstractMap就是一个骨架实现,具体不在深入。

2、”java只支持单继承”的一个误区
想起来以前又一次有人问我:extends后面不可能出现逗号分隔的对么?很多人看来是对的,其实不然,java只支持单继承这句话个人感觉是怪怪的,我觉得用java类只支持单继承比较恰当,因为接口是可以实现多继承的,比如说下面这段代码:

package com.brickworkers;

public interface Duo extends Sky, Sports{

}

那为什么会这样?如果可以支持多继承的话,假设两个父类中都有一个相同的方法,那么子类到底去执行哪个?但是接口就不一样,接口只表明有这么个方法,并不需要去实现。好了,只是想到所以拓展,再拓展就偏题了。

3、接口隔离原则(ISP)
以下是它的专业解释

客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。 -百度词条

既然命名都指定了接口,说明这条原则是针对接口的(但是个人看来,这原则不仅仅试用接口,抽象类也可以)。它主要表明接口的功能要单一,在实现这个接口的时候,接口中所有的方法对这个实现者来说都是必须的,也就是说在实现者看来这个接口是为他量身定做的。我们知道,接口中的方法在实现的时候都是被要求强制实现的,所以如果接口中有存在不是实现者要实现的方法,那么他还要被要求一同实现这个不必要方法,那么这么一来代码就显得很臃肿。解决办法就是遵循接口隔离原则对臃肿的接口进行拆分。
注意:接口隔离(ISP)并不等同于单一职责(SRP),因为SRP是针对与具体实现的,而ISP主要是针对抽象。

一个反例

你写了一个Operation接口,用于描述人的运动:

package com.brickworkers;

/**
 * @author Brickworker
 * Date:2017年4月9日下午1:32:50 
 * 关于接口Operation.java的描述:接口隔离原则
 * Copyright (c) 2017, brcikworker All Rights Reserved.
 */
public interface Operation {

    //散步
    public void walk();

    //跑步
    public void run();

    //足球
    public void football();

    //篮球
    public void basketball();
}

然后,现在要实现两类人群,篮球爱好者和足球爱好者:

//篮球爱好者
package com.brickworkers;

public class BasketBallPlayer implements Operation{

    @Override
    public void walk() {
        System.out.println("篮球运动员走路");
    }

    @Override
    public void run() {
        System.out.println("篮球运动员跑步");
    }

    @Override
    public void football() {//篮球运动员不会玩足球,所以这个方法实现为空
    }

    @Override
    public void basketball() {
        System.out.println("篮球运动员打篮球");
    }

}

//足球爱好者
package com.brickworkers;

public class FootballPlayer implements Operation{

    @Override
    public void walk() {
        System.out.println("足球运动员走路");
    }

    @Override
    public void run() {
        System.out.println("足球运动员跑步");
    }

    @Override
    public void football() {
        System.out.println("足球运动员踢足球");
    }

    @Override
    public void basketball() {//足球运动员并不会打篮球,所以该方法实现为空
    }

}

可能上面的例子很简短,所以有些小伙伴觉得这样实现也没有问题。这个例子只是一个比方,如果现实中一个借口冗余了很多的方法,实现的时候一半左右的方法是不必要的,那么重构是必然的。接下来,我们根据借口隔离原则,对上面的接口进行拆分,分为两步:①确立公共部分;②隔离个性部分。在上面的例子中,跑步和散步是两者都会的,所以可以合并为一个接口:

package com.brickworkers;

/**
 * @author Brickworker
 * Date:2017年4月9日下午1:50:17 
 * 关于接口CommOperation.java的描述:接口隔离原则拆分后的接口
 * Copyright (c) 2017, brcikworker All Rights Reserved.
 */
public interface CommOperation {
    //散步
    public void walk();

    //跑步
    public void run();
}

针对篮球爱好者和足球爱好者生成个性接口:

//篮球个性接口
package com.brickworkers;

public interface BasketballOperation {
    //篮球
    public void basketball();
}

//足球个性接口
package com.brickworkers;

public interface FootballOperation {
    //足球
    public void football();
}

那么,在实现的过程中就不一样了,具体看下面的BasketballPlayer类和Footballplayer类:

//篮球爱好者
package com.brickworkers;

public class BasketBallPlayer implements CommOperation, BasketballOperation{

    @Override
    public void walk() {
        System.out.println("篮球运动员走路");
    }

    @Override
    public void run() {
        System.out.println("篮球运动员跑步");
    }

    @Override
    public void basketball() {
        System.out.println("篮球运动员打篮球");
    }

}

//足球爱好者
package com.brickworkers;

public class FootballPlayer implements CommOperation, FootballOperation{

    @Override
    public void walk() {
        System.out.println("足球运动员走路");
    }

    @Override
    public void run() {
        System.out.println("足球运动员跑步");
    }

    @Override
    public void football() {
        System.out.println("足球运动员踢足球");
    }
}

这样,在实现者的角度看来,就非常的优雅。在现实中大型项目中,接口隔离显得尤为重要。话虽如此,但是有一说一,如果接口隔离开销还不足以弥补臃肿的开销,意思就是说为了不实现个别方法而单独开一个接口不划算的时候,不进行隔离,博主个人看来是可以理解的。

好了,今天的学习总结就到这里, 有什么问题请联系我,同时希望对大家有所帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值