设计模式-七大原则-依赖倒转原则

依赖倒转原则

基本介绍

高层模块不应该依赖底层模块,二者都应该依赖其抽象。
抽象不应该依赖细节,细节应该依赖抽象。
依赖倒转(倒置)的中心思想是面向接口编程。

依赖倒转原则是基于这样的的设计理念: 相对于细节的多变性,抽像的东西要稳定得多。
以抽象为基础搭建的架构比以细节为基础的架构要稳定得多。在java中,抽象指的是接口或者抽象类,
细节就是具体的实现类

使用接口或者抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成

问题代码示例

public class DependencyInversion {
    public static void main(String[] args) {
        Person person = new Person();
        person.receive(new Email());
    }
}

/**
 * 一个Person有一个接受消息的功能
 */
class Person {
    /**
     * 这里传入的参数是Email类,这样就直接依赖死了Email类
     * 如果我们还要接受的对象是 微信, QQ等消息,需要新增消息类,还要增加或重载receive方法
     * @param email 消息类
     */
    public void receive(Email email) {
        System.out.println(email.getInfo());
    }
}


class Email {
    public String getInfo() {
        return "电子邮件信息: hello";
    }
}

Person 类中的receive方法直接依赖了具体的Email类,这样对后期的扩展很不友好

使用依赖倒装,面向接口编程

/**
 * 根据依赖倒转优化后的代码
 */
public class DependencyInversion {
    public static void main(String[] args) {
        Person person = new Person();
        person.receive(new Email());
        person.receive(new QQ());
    }
}

/**
 * 一个Person有一个接受消息的功能
 */
class Person {
    /**
     * 采用依赖倒转,面向接口依赖,可以提高扩展性
     *
     * @param iReceiver 使用接口去依赖
     */
    public void receive(IReceiver iReceiver) {
        System.out.println(iReceiver.getInfo());
    }
}

/**
 * 电子邮件
 */
class Email implements IReceiver {

    @Override
    public String getInfo() {
        return "电子邮件信息: hello";
    }
}

class QQ implements IReceiver {

    @Override
    public String getInfo() {
        return "QQ信息: hello";
    }
}

/**
 * 定义IReceiver接口, 所有的消息类都实现这个接口
 */
interface IReceiver {
    public String getInfo();
}

将所有的消息类向上提取出一个接口或者抽象类,Person 类中的receive方法只需要依赖提取出的接口,这样提高了程序的扩展性

依赖传递的三种方式

接口方式传递

@SuppressWarnings("NonAsciiCharacters")
public class Test {
    public static void main(String[] args) {

        小米智能电视 小米智能电视 = new 小米智能电视();
        华为智能电视 华为智能电视 = new 华为智能电视();

        万能遥控器 w = new 万能遥控器();
        w.open(小米智能电视);
        w.open(华为智能电视);

        w.close(小米智能电视);
        w.close(华为智能电视);
    }
}


interface IOpenAndClose {
    /**
     * 抽象一个open方法,可以打开一个Tv
     */
    void open(ITv iTv);

    void close(ITv iTv);
}

interface ITv {
    /**
     * 抽象一个Tv上的关闭方法
     */
    void close();

    void open();
}

@SuppressWarnings("NonAsciiCharacters")
class 小米智能电视 implements ITv {
    @Override
    public void close() {
        System.out.println("我是小米智能电视,我关闭了");
    }

    @Override
    public void open() {
        System.out.println("我是小米智能电视,我打开了");
    }
}

@SuppressWarnings("NonAsciiCharacters")
class 华为智能电视 implements ITv {

    @Override
    public void close() {
        System.out.println("我是华为智能电视,我关闭了");
    }

    @Override
    public void open() {
        System.out.println("我是华为智能电视,我打开了");
    }
}

@SuppressWarnings("NonAsciiCharacters")
class 万能遥控器 implements IOpenAndClose {
    /**
     * 抽象一个open方法,可以打开一个Tv,
     * 因为是依赖的接口,所以只要是一个实现了ITv的电视都能被关闭
     *
     * @param iTv 不知道哪个品牌的电视机
     */
    @Override
    public void open(ITv iTv) {
        iTv.open();
    }

    @Override
    public void close(ITv iTv) {
        iTv.close();
    }
}

构造方式传递

@SuppressWarnings("NonAsciiCharacters")
public class Test {
    public static void main(String[] args) {
        小米智能电视 小米智能电视 = new 小米智能电视();
        万能遥控器 万能遥控器 = new 万能遥控器(小米智能电视);
    }
}

interface IOpenAndClose{
    /**
     * 注意这里是空参的,没有依赖接口
     */
    void open();
    void close();
}

interface ITv{
    void open();
    void close();
}

@SuppressWarnings("NonAsciiCharacters")
class 小米智能电视 implements ITv{

    @Override
    public void open() {
        System.out.println("我是小米智能电视,我打开了");
    }

    @Override
    public void close() {
        System.out.println("我是小米智能电视,我关闭了");
    }
}

@SuppressWarnings("NonAsciiCharacters")
class 万能遥控器 implements IOpenAndClose{

    // 使用成员变量的形式,注入依赖
   private ITv iTv;

    /**
     * 注意这里是空参的,没有依赖接口
     */
    @Override
    public void open() {
        this.iTv.open();
    }

    @Override
    public void close(){
        this.iTv.close();
    }

    private 万能遥控器(){

    }

    /**
     * 使用构造的方式给成员变量赋值
     * @param iTv 某个型号的电视
     */
   public 万能遥控器(ITv iTv){
        this.iTv = iTv;
    }
}

setter方式传递

@SuppressWarnings("NonAsciiCharacters")
public class Test {
    public static void main(String[] args) {
        小米智能电视 小米智能电视 = new 小米智能电视();
        万能遥控器 万能遥控器 = new 万能遥控器();
        万能遥控器.setiTv(小米智能电视);
        万能遥控器.close();
    }
}

interface IOpenAndClose {
    /**
     * 注意这里是空参的,没有依赖接口
     */
    void open();

    void close();
}

interface ITv {
    void open();

    void close();
}

@SuppressWarnings("NonAsciiCharacters")
class 小米智能电视 implements ITv {

    @Override
    public void open() {
        System.out.println("我是小米智能电视,我打开了");
    }

    @Override
    public void close() {
        System.out.println("我是小米智能电视,我关闭了");
    }
}

@SuppressWarnings("NonAsciiCharacters")
class 万能遥控器 implements IOpenAndClose {

    // 使用成员变量的形式,注入依赖
    private ITv iTv;

    /**
     * 注意这里是空参的,没有依赖接口
     */
    @Override
    public void open() {
        if (iTv == null) {
            System.out.println("没有找到电视");
        } else {
            this.iTv.open();
        }
    }

    @Override
    public void close() {
        if (iTv == null) {
            System.out.println("没有找到电视");
        } else {
            this.iTv.close();
        }
    }

    /**
     * 使用set的方式给成员变量赋值
     *
     * @param iTv 某个型号的电视
     */
    public void setiTv(ITv iTv) {
        this.iTv = iTv;
    }
}

依赖倒转的原则和注意事项

  • 底层模块尽量都要有抽象类或者接口,或者两者都有,程序的稳定性更好。
  • 变量的声明类型尽量是抽象或者接口,这样我们的变量引用和实际对象间,就存在一个缓冲。
  • 继承时遵循里氏替换原则
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值