精华内容
下载资源
问答
  • 主要介绍了PHP依赖倒置(Dependency Injection)代码实例本文只提供实现代码,需要的朋友可以参考下
  • 一、依赖倒置原则简介、 二、面向实现编程代码示例 ( 反面示例 )、 ...三、依赖倒置原则代码示例 ( 推荐示例 | 使用接口方法注入 IGood 实现类 )、 1、顾客类、 2、商品接口、 3、冰箱商品、 4、电视商品、 5、测试类、





    一、依赖倒置原则简介



    依赖倒置原则 : 高层模块 不应该 依赖 低层模块 , 二者都应该 依赖其抽象 ;
    抽象 不应该 依赖细节 , 细节应该依赖抽象 ;

    针对接口编程 , 不要针对实现编程 ;


    通过抽象 , 包括使用 接口 或 抽象类 , 使个各类或模块之间 彼此独立 , 互不影响 , 从而实现模块之间的 松耦合 , 降低模块间的耦合性 ;

    使用依赖倒置原则时的注意点 :

    • 每个类都 尽量 实现自接口继承抽象类 ;
    • 尽量 避免从具体的类派生 ;
    • 尽量 不要覆盖基类方法 ;

    依赖倒置原则的优点 : 减少类之间的 耦合性 , 提高系统 稳定性 , 提高 代码可读性 , 可维护性 , 可 降低修改程序所造成的风险 ;





    二、面向实现编程代码示例 ( 反面示例 )




    1、顾客类


    package dependenceinversion;
    
    /**
     * 如果要增加一个新功能 , 就需要在该类中添加一个新方法
     *      这就是面向实现编程 , 该实现类需要经常进行修改
     *      扩展性很差
     *
     * 应用层的函数 , 是依赖于底层实现的 , 由于没有实现接口
     *      造成了应用层的测试类 , 直接依赖于本类
     *      应用层的模块属于高层模块
     *      本类属于低层模块
     *      根据依赖倒置原则 , 高层次的模块是不应该依赖于低层次的模块的
     */
    public class Customer {
        public void buyFridge() {
            System.out.println("购买冰箱");
        }
    
        public void buyTelevision() {
            System.out.println("购买电视");
        }
    }
    

    2、测试类


    package dependenceinversion;
    
    public class Main {
        public static void main(String[] args) {
            Customer customer = new Customer();
            customer.buyFridge();
            customer.buyTelevision();
        }
    }
    

    执行结果 :

    购买冰箱
    购买电视
    

    在这里插入图片描述





    三、依赖倒置原则代码示例 ( 推荐示例 | 使用接口方法注入 IGood 实现类 )




    1、顾客类


    使用接口方法注入 IGood 实现类 ;

    package dependenceinversion;
    
    public class Customer {
        /**
         * 接口方法注入 IGood 实现类
         *      也可以使用构造函数 , 注入 IGood 实现类
         *
         * 此处就是面向接口编程
         *      如果添加了新的类 , 不需要修改本类
         *      只需要添加新的接口实现类即可
         *      面向接口编程 , 而不是面向本实现类
         *      对于高层模块来说 , 具体传入的参数是什么参数 ,
         *      交给高层模块选择
         *
         * 本类 与 具体的 IGood 接口 实现 是解耦的
         *      本类 与 应用层 客户端测试类 之间是解耦的
         *
         * 如果在添加一个新商品 , 直接定义一个新的接口实现类即可
         *
         * @param iGood
         */
        public void buy(IGood iGood) {
            iGood.buy();
        }
    }
    

    2、商品接口


    package dependenceinversion;
    
    /**
     * 商品接口
     */
    public interface IGood {
        /**
         * 购买商品
         */
        void buy();
    }
    

    3、冰箱商品


    package dependenceinversion;
    
    /**
     * 冰箱商品
     */
    public class FridgeGood implements IGood {
        @Override
        public void buy() {
            System.out.println("购买冰箱");
        }
    }
    

    4、电视商品


    package dependenceinversion;
    
    /**
     * 电视商品
     */
    public class TelevisionGood implements IGood {
        @Override
        public void buy() {
            System.out.println("购买电视");
        }
    }
    

    5、测试类


    package dependenceinversion;
    
    public class Main {
        public static void main(String[] args) {
            Customer customer = new Customer();
            customer.buy(new FridgeGood());
            customer.buy(new TelevisionGood());
        }
    }
    

    执行结果 :

    购买冰箱
    购买电视
    

    在这里插入图片描述





    四、依赖倒置原则代码示例 ( 推荐示例 | 使用构造函数注入 IGood 实现类 )




    1、顾客类


    使用构造函数注入 IGood 实现类 ;

    package dependenceinversion;
    
    public class Customer {
        private IGood iGood;
    
        /**
         * 使用构造函数注入 IGood 实现类
         * @param iGood
         */
        public Customer(IGood iGood) {
            this.iGood = iGood;
        }
    
        public void buy() {
            this.iGood.buy();
        }
    }
    

    2、商品接口


    package dependenceinversion;
    
    /**
     * 商品接口
     */
    public interface IGood {
        /**
         * 购买商品
         */
        void buy();
    }
    

    3、冰箱商品


    package dependenceinversion;
    
    /**
     * 冰箱商品
     */
    public class FridgeGood implements IGood {
        @Override
        public void buy() {
            System.out.println("购买冰箱");
        }
    }
    

    4、电视商品


    package dependenceinversion;
    
    /**
     * 电视商品
     */
    public class TelevisionGood implements IGood {
        @Override
        public void buy() {
            System.out.println("购买电视");
        }
    }
    

    5、测试类


    package dependenceinversion;
    
    public class Main {
        public static void main(String[] args) {
            Customer customer = new Customer(new FridgeGood());
            customer.buy();
    
            Customer customer2 = new Customer(new TelevisionGood());
            customer2.buy();
        }
    }
    

    执行结果 :

    购买冰箱
    购买电视
    

    在这里插入图片描述





    五、依赖倒置原则代码示例 ( 推荐示例 | 使用 Setter 方法注入 IGood 实现类 )




    1、顾客类


    使用 Setter 方法注入 IGood 实现类 ;

    package dependenceinversion;
    
    public class Customer {
        private IGood iGood;
    
        public void setiGood(IGood iGood) {
            this.iGood = iGood;
        }
    
        public void buy() {
            this.iGood.buy();
        }
    }
    

    2、商品接口


    package dependenceinversion;
    
    /**
     * 商品接口
     */
    public interface IGood {
        /**
         * 购买商品
         */
        void buy();
    }
    

    3、冰箱商品


    package dependenceinversion;
    
    /**
     * 冰箱商品
     */
    public class FridgeGood implements IGood {
        @Override
        public void buy() {
            System.out.println("购买冰箱");
        }
    }
    

    4、电视商品


    package dependenceinversion;
    
    /**
     * 电视商品
     */
    public class TelevisionGood implements IGood {
        @Override
        public void buy() {
            System.out.println("购买电视");
        }
    }
    

    5、测试类


    package dependenceinversion;
    
    public class Main {
        public static void main(String[] args) {
            Customer customer = new Customer();
    
            customer.setiGood(new FridgeGood());
            customer.buy();
    
            customer.setiGood(new TelevisionGood());
            customer.buy();
        }
    }
    

    执行结果 :

    购买冰箱
    购买电视
    

    在这里插入图片描述

    展开全文
  • 代码库解释依赖倒置原则 本练习的目标是开发依赖倒置原则 (DIP)。 您的任务:用 OpenStreetMapGeocoding 替换 GoogleGeocoding,并通过这样做来识别和纠正 DIP 违规。
  • 依赖倒置

    2019-09-24 00:37:12
    用途:用于巩固设计模式中的依赖倒置模式 依赖倒置原则的定义依赖倒置原则(Dependence Inversion Principle,DIP)是 Object Mentor 公司总裁罗伯特·马丁(Robert C.Martin)于 1996 年在 C++ Report 上发表的...

    用途:用于巩固设计模式中的依赖倒置模式

    依赖倒置原则的定义
    依赖倒置原则(Dependence Inversion Principle,DIP)是 Object Mentor 公司总裁罗伯特·马丁(Robert C.Martin)于 1996 年在 C++ Report 上发表的文章。
    依赖倒置原则的原始定义为:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象.
    依赖倒置原则是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合。

    由于在软件设计中,细节具有多变性,而抽象层则相对稳定,因此以抽象为基础搭建起来的架构要比以细节为基础搭建起来的架构要稳定得多。这里的抽象指的是接口或者抽象类,而细节是指具体的实现类。
    使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给它们的实现类去完成。

    依赖、倒置原则的作用

    依赖倒置原则的主要作用如下。
    依赖倒置原则可以降低类间的耦合性。
    依赖倒置原则可以提高系统的稳定性。
    依赖倒置原则可以减少并行开发引起的风险。
    依赖倒置原则可以提高代码的可读性和可维护性。

    依赖倒置原则的实现方法

    依赖倒置原则的目的是通过要面向接口的编程来降低类间的耦合性,所以我们在实际编程中只要遵循以下4点,就能在项目中满足这个规则。
    每个类尽量提供接口或抽象类,或者两者都具备。
    变量的声明类型尽量是接口或者是抽象类。
    任何类都不应该从具体类派生。
    使用继承时尽量遵循里氏替换原则。


    上面讲了这么多,都是从网上抄的,我们可以理解为面向接口编程。
    设想一下,我们有这样一个需求,分别想知道两个购物网站的商品,按照常规,我们会这样写。

    /*京东继承SHOP接口,实现接口的方法*/
        class jingdong  {
            public String sell() {
                return "京东有奶茶妹妹";
            }
        }
        /*淘宝继承SHOP接口,实现接口的方法*/
        class taobao  {
            public String sell() {
                return "淘宝没有奶茶妹妹";
            }
        }
    class Customer {
            //调用接口,实例化时,由用户决定实例化具体类
            public void shopping(taobao shop) {
                System.out.println(shop.sell());
            }
        }
         public static void main(String[] args) {
        Customer customer = new Customer();//如果想知道京东有什么产品就会很麻烦,要更改Customer类中方法shopping的形参,如果想同时知道京东和淘宝都卖什么产品,实现起来很麻烦
        customer.shopping();
    }

    顾客每更换一家商店,都要修改一次代码,这明显违背了开闭原则。存在以上缺点的原因是:顾客类设计时同具体的商店类绑定了,这违背了依赖倒置原则。
    这时,我们可以抽象一个共同的Shop接口,这样,不管顾客类 Customer 访问什么商店,或者增加新的商店,都不需要修改原有代码了,其类图如下所示。

     

    所有代码如下:
    package keivn.LSTH.DIP;
    
    /*依赖倒置
     * 高层模块不应该依赖低层模块,两者都应该依赖其抽象;
     * 抽象不应该依赖细节,细节应该依赖抽象
     * 面向接口编程
     * */
    public class DIPTest {
        public static void main(String[] args) {
            Customer customer = new Customer();
            customer.shopping(new jingdong());
            customer.shopping(new taobao());
        }
    }
    /* 卖东西的接口 */
    interface shop {
        /* 卖东西的接口 */
        public String sell();
    }
    /* 京东继承SHOP接口,实现接口的方法 */
    class jingdong implements shop {
        public String sell() {
            return "京东有奶茶妹妹";
        }
    }
    /* 淘宝继承SHOP接口,实现接口的方法 */
    class taobao implements shop {
        public String sell() {
            return "淘宝没有奶茶妹妹";
        }
    }
    class Customer {
        // 调用接口,实例化时,由用户决定实例化具体类
        public void shopping(shop shop) {
            System.out.println(shop.sell());
        }
    }

    程序的运行结果如下:

    京东有奶茶妹妹
    淘宝没有奶茶妹妹

     

    转载于:https://www.cnblogs.com/c546170667/articles/11383391.html

    展开全文
  • 依赖倒置原则

    2021-01-01 20:08:50
    依赖倒置原则(Dependence Inversion Principle,DIP)指设计代码结构时,高层模块不应该依赖底层模块,二者都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象。通过依赖倒置,可以降低类与类之间的耦合性,...

    依赖倒置原则的定义

    依赖倒置原则(Dependence Inversion Principle,DIP)指设计代码结构时,高层模块不应该依赖底层模块,二者都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象。通过依赖倒置,可以降低类与类之间的耦合性,提高系统的稳定性,提高代码的可读性和可维护性,并降低修改程序带来的风险。

    示例

    • 首先创建一个课程的抽象接口ICourse
    package com.liguogang.DIP;
    
    public interface ICourse {
        void study();
    }
    
    
    • 然后写EnglishCourse类
    package com.liguogang.DIP;
    
    public class EnglishCourse implements ICourse {
        @Override
        public void study() {
            System.out.println("学习英语课");
        }
    }
    
    
    • 再实现MathCourse类
    package com.liguogang.DIP;
    
    public class MathCourse implements ICourse {
        @Override
        public void study() {
            System.out.println("学习数学课");
        }
    }
    
    
    1. 创建Person类(依赖注入:构造器注入)
    package com.liguogang.DIP;
    /**
     * 依赖注入:构造器注入
     */
    public class Person {
        public void study(ICourse course) {
            course.study();
        }
    }
    
    

    1.1 客户端调用代码

    package com.liguogang.DIP;
    
    public class Test {
        public static void main(String[] args) {
            // 依赖注入:构造器注入
            Person person = new Person();
            person.study(new EnglishCourse());
        }
    }
    
    

    2.1 如果Person 是全局单例,修改Persion类(依赖注入:Setter注入)

    package com.liguogang.DIP;
    
    /**
     * 依赖注入:Setter注入
     */
    public class Person {
        
        private ICourse course;
    
        public void setCourse(ICourse course) {
            this.course = course;
        }
    
        public void study(){
            course.study();
        }
    }
    
    

    2.2 客户端调用代码

    package com.liguogang.DIP;
    
    public class Test {
        public static void main(String[] args) {
            // 依赖注入:Setter注入
            Person person = new Person();
            person.setCourse(new EnglishCourse());
            person.study();
    
            person.setCourse(new MathCourse());
            person.study();
        }
    }
    
    

    结果:
    在这里插入图片描述
    代码地址:https://github.com/lee58/designPattern/tree/master

    展开全文
  • 时间告诉我,无理取闹的年龄过了,该懂事了 前言 上一篇,我们讲了 ISP 原则,知道了在设计接口的时候,我们应该设计小接口,不应该让使用者依赖于用不到的方法。...依赖倒置原则(Dependency inversi.

    时间告诉我,无理取闹的年龄过了,该懂事了

    前言

    上一篇,我们讲了 ISP 原则,知道了在设计接口的时候,我们应该设计小接口,不应该让使用者依赖于用不到的方法。

    依赖这个词,程序员们都好理解,意思就是,我这段代码用到了谁,我就依赖了谁。依赖容易有,但能不能把依赖弄对,就需要动点脑子了。如果依赖关系没有处理好,就会导致一个小改动影响一大片,而把依赖方向搞反,就是最典型的错误。

    那什么叫依赖方向搞反呢?我们就来讨论关于依赖的设计原则:依赖倒置原则。

    谁依赖谁

    依赖倒置原则(Dependency inversion principle,简称 DIP)是这样表述的:

    高层模块不应依赖于低层模块,二者应依赖于抽象。

    抽象不应依赖于细节,细节应依赖于抽象。

    学习这个原则,最重要的是要理解“倒置”,而要理解什么是“倒置”,就要先理解所谓的“正常依赖”是什么样的。

    我们很自然地就会写出类似下面的这种代码:

    class CriticalFeature {
      private Step1 step1;
      private Step2 step2;
      ...
      
      void run() {
        // 执行第一步
        step1.execute();
        // 执行第二步
        step2.execute();
        ...
      }
    }
    

    但是,这种未经审视的结构天然就有一个问题:高层模块会依赖于低层模块。在上面这段代码里,CriticalFeature 类就是高层类,Step1 和 Step2 就是低层模块,而且 Step1 和 Step2 通常都是具体类。虽然这是一种自然而然的写法,但是这种写法确实是有问题的。

    在实际的项目中,代码经常会直接耦合在具体的实现上。比如,我们用 Kafka 做消息传递,我们就在代码里直接创建了一个 KafkaProducer 去发送消息。我们就可能会写出这样的代码:

    class Handler {
      private KafkaProducer producer;
      
      void send() {
        ...
        Message message = ...;
        producer.send(new KafkaRecord<>("topic", message);
        ...
      }
    }
    

    也许你会问,我就是用了 Kafka 发消息,创建一个 KafkaProducer,这有什么问题吗?其实,我们需要站在长期的角度去看,什么东西是变的、什么东西是不变的。Kafka 虽然很好,但它并不是系统最核心的部分,我们在未来是可能把它换掉的。

    你可能会想,这可是我实现的一个关键组件,我怎么可能会换掉它呢?软件设计需要关注长期、放眼长期,所有那些不在自己掌控之内的东西,都是有可能被替换的。其实,替换一个中间件是经常发生的。所以,依赖于一个可能会变的东西,从设计的角度看,并不是一个好的做法。那我们应该怎么做呢?这就轮到倒置登场了。

    所谓倒置,就是把这种习惯性的做法倒过来,让高层模块不再依赖于低层模块。那要是这样的话,我们的功能又该如何完成呢?计算机行业中一句名言告诉了我们答案:

    计算机科学中的所有问题都可以通过引入一个间接层得到解决。

    是的,引入一个间接层。这个间接层指的就是 DIP 里所说的抽象。也就是说,这段代码里面缺少了一个模型,而这个模型就是这个低层模块在这个过程中所承担的角色。

    既然这个模块扮演的就是消息发送者的角色,那我们就可以引入一个消息发送者(MessageSender)的模型:

    interface MessageSender {
      void send(Message message);
    }
    
    class Handler {
     
      void send(MessageSender sender) {
        ...
        sender.send(message);
        ...
      }
    }
    

    有了消息发送者这个模型,那我们又该如何把 Kafka 和这个模型结合起来呢?那就要实现一个 Kafka 的消息发送者:

    class KafkaMessageSender implements MessageSender {
        
      private KafkaProducer producer;
      
      public void send(final Message message) {
        this.producer.send(new KafkaRecord<>("topic", message));
      }
    }
    

    消费者可以这样消费消息:

    Handler handler = new Handler();
    handler.send(new KafkaMessageSender());
    

    这样一来,高层模块就不像原来一样直接依赖低层模块,而是将依赖关系“倒置”过来,让低层模块去依赖由高层定义好的接口。这样做的好处就在于,将高层模块与低层实现解耦开来。

    img

    如果未来我们要用RabbitMQ替换掉 Kafka,只要重写一个 MessageSender 就好了,其他部分并不需要改变。这样一来,我们就可以让高层模块保持相对稳定,不会随着低层代码的改变而改变。

    class RabbitmqMessageSend implements MessageSender {
        
      private RabbitTemplate rabbitTemplate;
      
      public void send(final Message message) {
        rabbitTemplate.setExchange(exchangeKey);
        rabbitTemplate.setRoutingKey(routingKey);
        CorrelationData correlationId = new CorrelationData(UUID.randomUUID().toString());
        this.rabbitTemplate.convertAndSend(exchangeKey,routingKey,message,correlationId);
      }
    }
    

    消费者可以这样消费消息:

    Handler handler = new Handler();
    handler.send(new RabbitmqMessageSend());
    

    依赖于抽象

    抽象不应依赖于细节,细节应依赖于抽象。

    其实,这个可以更简单地理解为一点:依赖于抽象,从这点出发,我们可以推导出一些更具体的指导编码的规则:

    • 任何变量都不应该指向一个具体类;
    • 任何类都不应继承自具体类;
    • 任何方法都不应该改写父类中已经实现的方法。

    举个List 声明的例子,其实背后遵循的就是这里的第一条规则:

    List<String> list = new ArrayList<>();
    

    在实际的项目中,这些编码规则有时候也并不是绝对的。如果一个类特别稳定,我们也是可以直接用的,比如字符串类。但是,请注意,这种情况非常少。因为大多数人写的代码稳定度并没有那么高。所以,上面几条编码规则可以成为覆盖大部分情况的规则,出现例外时,我们就需要特别关注一下。

    总结

    1. 如果说实现开闭原则的关键事抽象化,是面向对象设计的目标的话,依赖倒置原则就是这个面向对象设计的主要机制。
    2. 依赖倒置原则的目的是通过要面向接口的编程来降低类间的耦合性,所以我们在实际编程中只要遵循以下4点,就能在项目中满足这个规则:
      • 每个类尽量提供接口或抽象类,或者两者都具备。
      • 变量的声明类型尽量是接口或者是抽象类。
      • 任何类都不应该从具体类派生。
      • 使用继承时尽量遵循里氏替换原则。
    展开全文
  • 代码库解释依赖倒置原则 工作正在进行中。
  • ioc 依赖倒置 今天,我们将讨论所有主题中最令人困惑的主题之一,看看我们能否解开依赖倒置,控制倒置和依赖注入的混乱局面。 理解每个名称的细节并不完全重要,因为许多人最终会互换使用它们。 我们不太可能要纠正...
  • 开闭原则 依赖倒置原则 到目前为止,我们只研究了单一职责,打开/关闭,liskov替换和接口隔离原则。依赖倒置是我们所要研究的最后一个原理之一。 该原则指出 答:高级模块不应依赖于低级模块。 两者都应依赖抽象。...
  • 代码重构:根据依赖倒置原则来解决循环依赖的问题背景重构解决方案 背景 最近项目进入推广期,新需求开始变少,闲来无事便想着重构一下之前的代码,之前为了快速迭代上线,没有仔细考虑代码的结构,导致代码结构混乱...
  • PHP依赖倒置(Dependency Injection)代码实例,依赖倒置原则实现类:代码如下:class Container{protected $setings = array();public function set($abstract, $concrete = null){if ($concrete === null) {$concrete...
  • c++依赖倒置原则

    千次阅读 2017-10-17 13:19:42
    C++依赖倒置原则

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 30,752
精华内容 12,300
关键字:

依赖倒置代码