加油.png

在之前的一篇博客 Java Builder 模式,你搞懂了么? 中,我们提到了在 oop 编码设计中 只要能拿到类的实例,即对象,就能命令对象做一系列事情了。在 java/android 程序中,每个功能模块都由 n 个 类所组成,而每个类都封装了各自的功能,我们实例化每个类的实例,分别命令他们去完成指定的功能,但是,程序设计中,类之间往往不是单独去完成任务的,他们存在相互依赖的关系,就比如 A 类依赖 B 类,B 类又依赖 C 类,A 类 又同时依赖 C 类等等。这样构成了一个错综复杂的关系网。先来个简单代码直观的感受~

还是以 制造 car 为例子。CarCreateTechnology 制造汽车的技术封装接口。

1public interface CarCreateTechnology {2    String createCar();3}

CarAutoCreate 制造汽车的技术封装接口的实现类,具体逻辑由他实现。

1public class  CarAutoCreate implements CarCreateTechnology{2    @Override3    public String createCar() {4        return "自动生产的 car ~";5    }6}

CarFactory 汽车工厂类:

 1public class CarFactory { 2    private CarCreateTechnology mCreateTechnology; 3 4    public CarFactory() { 5        mCreateTechnology = new CarAutoCreate(); 6    } 7    public String createCar(){ 8        return mCreateTechnology.createCar(); 9    }10}

最终 实例化 CarFactory 调用 createCar() 方法生产出 car
String car = new CarFactory().createCar();哈哈,这样我们的 car 就生产好啦,貌似很简单嘛。

嘟嘟~车开着正起劲的时候,有位客户说了,不喜欢自动生产的汽车,想请个专业人员整一辆定制 car。这时候有人说这还不简单,噼里啪啦的敲敲敲,代码修改如下:

Creater:定制 car 的制作者:

 1public class Creater { 2    private String name;//汽车制造者名字 3    private String carType;//d定制 car 的类型 4 5    public Creater(String name, String carType) { 6        this.name = name; 7        this.carType = carType; 8    } 9    public String createCar(){10        return this.carType;11    }12}

CarAutoCreate 制造汽车的技术封装接口的实现类:

 1public class CarAutoCreate implements CarCreateTechnology { 2    private Creater mCreater;//定制 car 的制作者 3 4    public CarAutoCreate(Creater creater) { 5        mCreater = creater; 6    } 7 8    @Override 9    public String createCar() {10        return mCreater.createCar();11    }12}

CarFactory 汽车工厂类:

 1public class CarFactory { 2    private CarCreateTechnology mCreateTechnology; 3 4    public CarFactory(Creater creater) { 5        mCreateTechnology = new CarAutoCreate(creater); 6    } 7    public String createCar(){ 8        return mCreateTechnology.createCar(); 9    }10}

最后 调用 String car = new CarFactory(new Creater("张少林", "宝马")).createCar();我们的定制 car "宝马" 就被制造出来啦。这样修改起来貌似挺简单的,但是存在以下一些问题

分析问题

  • CarFactory 类 依赖 CarAutoCreate 类。需要在 CarFactory 中持有 CarAutoCreate 实例。而我们在 CarFactory 的构造中强行初始化了 CarAutoCreate,这就使得 CarFactory 与 CarAutoCreate 紧紧耦合在一起。这就是传说中的硬初始化(hard init)
  • 一旦 CarAutoCreate 的构造发生了变化,比如上面我们增加了 Creater .这使得 CarFactory 也要被迫做出修改。
  • 这种耦合度在程序相对简单的情况下,修改也就修改嘛,ide 打代码挺快的,但是一旦程序变得越来越复杂,依赖 CarAutoCreate 的地方非常多的情况下,修改起来就不辣么容易了,我们需要付出相当多的劳动力去修改代码,浪费时间不说,还很有可能因为修改失误而造成难以查找的错误,加大我们的工作量。

知道了问题所在,我们来想办法解决,毕竟不喜欢偷懒的程序员不是好程序员,我们需要写出一手优雅的代码。

解决问题——依赖注入

java 中常见的依赖注入有三种:

一、作为构造函数的参数注入

我们修改一下 CarFactory 的构造,将 CarCreateTechnology 作为参数传入,在构造中初始化全局 CarCreateTechnology 。

 1public class CarFactory { 2    private CarCreateTechnology mCreateTechnology; 3 4    public CarFactory(CarCreateTechnology createTechnology) { 5        mCreateTechnology = createTechnology; 6    } 7 8    public String createCar(){ 9        return mCreateTechnology.createCar();10    }11}

调用:String car = new CarFactory(new CarAutoCreate(new Creater("张少林", "宝马"))).createCar();结果是一样的,定制 car 一样制造成功。但是不同的是:我们没有在 CarFactory 构造中直接构造所依赖的类(CarAutoCreate),而是通过传入形参,由最终调用方去初始化依赖类,这样就解决了之前的硬初始化问题,实现了解耦,提高了程序的可拓展性、可维护性。 眼毒的同学肯定发现了,我们的 CarAutoCreate 就是通过构造方法依赖注入所需的依赖(Creater)。

二、提供 Setter 设置值注入

CarFactory 添加 setxxx 注入全局变量。

 1public class CarFactory { 2    private CarCreateTechnology mCreateTechnology; 3 4    public void setCreateTechnology(CarCreateTechnology createTechnology) { 5        mCreateTechnology = createTechnology; 6    } 7 8    public String createCar(){ 9        return mCreateTechnology.createCar();10    }11}

调用:

1CarFactory carFactory = new CarFactory(); 2 carFactory.setCreateTechnology(new CarAutoCreate(new Creater("张少林","宝马")));3 String car = carFactory.createCar();

这种方法也是提供方法设置属性进去,同样也没有直接在 CarFactory 中直接实例化依赖类,而是最终调用的时候初始化设置进去,同样达到解耦目的。

三、接口注入

接口注入跟 Setter 注入类似,只是用接口包装了 Sertter 方法。这种方式易于管理。

1public interface InjectTechnology {2    void injectCreate(CarCreateTechnology carCreateTechnology);3}

CarFactory 实现接口。复写方法。在方法中注入。、

 1public class CarFactory implements InjectTechnology{ 2    private CarCreateTechnology mCreateTechnology; 3 4    public String createCar(){ 5        return mCreateTechnology.createCar(); 6    } 7 8    @Override 9    public void injectCreate(CarCreateTechnology carCreateTechnology) {10        this.mCreateTechnology = carCreateTechnology;11    }12}

"硬编码" 和 "软编码",图片来自网络

编码方式区别.png

最后,应该有的思考

我们在 oop 编码设计中,应该尽可能的让依赖类在最上层初始化,在细节中杜绝硬编码。编写解耦,有可拓展性、可维护性的代码。

更多原创文章会在公众号第一时间推送,欢迎扫码关注 张少林同学

张少林同学.jpg

转载于:https://www.cnblogs.com/zhangshaolin/p/10172730.html

解耦技巧——依赖注入!相关推荐

  1. php 依赖注入框架,通过实现依赖注入和路由,构建一个自己的现代化PHP框架

    如何提高自己编写代码的能力呢?我们首先想到的是阅读学习优秀的开源项目,然后写一个自己的web框架或类库组件.作为web开发者,我们通常都是基于面向对象OOP来开发的,所以面向对象的设计能力或者说设计模 ...

  2. PHP进阶学习之依赖注入与Ioc容器详解

    背景 在很多编程语言(例如java)开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,一旦有修改,牵扯的类会很多 ...

  3. 【 .NET Core 3.0 】框架之九 || 依赖注入 与 IoC

    本文有配套视频:https://www.bilibili.com/video/av58096866/?p=5 前言 1.重要:如果你实现了解耦,也就是 api 层只引用了 IService 和 IRe ...

  4. laravel 核心架构(1)服务容器-深入理解控制反转(IoC)和依赖注入(DI)

    1. 介绍 laravel 容器 存放的 是对象.对象的描述(类.接口)或者是提供对象的回调,通过这种容器,我们得以实现许多高级的功能,其中最常提到的,就是 "解耦"." ...

  5. Spring的IOC(依赖注入和控制反转)

    Spring框架面试笔试必问之一!非常重要也非常强大,说实话一开始仿照着Spring MVC配置搭建起来,再写几句增删改查,真的配不上叫做学会了那个框架.框架是N种优秀的设计模式和一些很高深的技术组合 ...

  6. ASP.NET CORE 第四篇 依赖注入IoC学习 + AOP界面编程初探

    原文作者:老张的哲学 更新 1.如果看不懂本文,或者比较困难,先别着急问问题,我单写了一个关于依赖注入的小Demo,可以下载看看,多思考思考注入的原理: https://github.com/anjo ...

  7. 从壹开始前后端分离【 .NET Core2.2 +Vue2.0 】框架之九 || 依赖注入IoC学习 + AOP界面编程初探...

    更新 1.如果看不懂本文,或者比较困难,先别着急问问题,我单写了一个关于依赖注入的小Demo,可以下载看看,多思考思考注入的原理: https://github.com/anjoy8/BlogArti ...

  8. 控制反转IOC、依赖注入DI的详细说明与举例

    文章目录 引入 IOC介绍 IOC的实现 通过构造函数注入依赖 通过 setter 设值方法注入依赖 依赖注入容器 IOC优缺点 优点 缺点 阅读时忽略语言差异,参考了很多其他博主内容,参考博文在最后 ...

  9. Swift中依赖注入的解耦策略

    原文地址:Dependency Injection Strategies in Swift 简书地址:Swift中依赖注入的解耦策略 今天我们将深入研究Swift中的依赖注入,这是软件开发中最重要的技 ...

  10. 依赖注入?依赖注入是如何实现解耦的?

    如何用最简单的方式解释依赖注入?依赖注入是如何实现解耦的? 第一章:小明和他的手机 从前有个人叫小明 小明有三大爱好,抽烟,喝酒-- 咳咳,不好意思,走错片场了.应该是逛知乎.玩王者农药和抢微信红包 ...

最新文章

  1. 根据总用量计算每种包装规格的购买量和总价
  2. java企业网站源码,模版,有前后台,springmvcSSM,生成静态化
  3. 云计算技术 — 云计算技术发展编年史
  4. python 标准差内数据概率怎么求_Python-统计概率
  5. TimingWheel 时间轮详解
  6. windows下集成maven+eclipse开发环境二:集成maven到eclipse,并使用nexus作为maven仓库...
  7. html5 客户端数据缓存机制,深入理解HTML5离线缓存机制
  8. MySQL 中文的乱码问题
  9. 一行python代码查找中文同义词(synonyms)
  10. ipmitool源码解析(一)——一次带内ipmitool raw data发送过程
  11. 新更新....llq原创考试第二题
  12. 【亲测】服务器事件查看器打不开报错,mmc无法创建管理单元怎么办
  13. 红米note4 android8.0,红米Note 4首个安卓8.0刷机包放出,开发者:可日常使用
  14. Android UI线程
  15. AURIX TriCore学习笔记四:LwIP裸机移植
  16. c#如何wmf图片转换成png图片_C#图片格式转换(支持bmp/gif/jpeg/png/tiff/wmf文件)
  17. 苹果xsmax怎么开机_苹果xsmax触屏不灵敏,xsmax触屏失灵怎么回事
  18. Openvino 模型转换命令mo.py
  19. 曾经我创办了个公司,然后被投资人踢出去了......
  20. android notification设置提示音

热门文章

  1. css类命名_标题CSS:CSS类命名的简单方法
  2. SpringBoot中Starters是什么
  3. POJ1759Garland题解
  4. html5绘制心形图案,HTML5/Canvas 渐变色彩的心形图案
  5. AOSP、AOKP、CM的区别
  6. 欢迎使用CSDN-markdown编辑器恢复看电视剧弗兰克的说法
  7. Stata新命令:psestimate - 倾向得分匹配中协变量的筛选
  8. 你鼓舞了我是世界杯主题曲吗_20位鼓舞人心的科技女性
  9. Java 微信企业付款到零钱
  10. php报错_STORAGE_WRITE_ERROR_:./Application/Runtime/Cache/Admin/df12aa1edf6tt330187a6514aae4fda4.php