本篇文章来自leobert_lan的投稿,分享了他对面向对象设计的了解,希望对大家有所帮助!同时也感谢作者贡献的精彩文章。
https://blog.csdn.net/a774057695
/ 什么是DI,什么是IoC /
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度
我们看一下改进后的例子: 注:限于篇幅,我不展示每一步重构,直接展示一个相对完善的阶段性成果
到这里,我们应该可以体会,IoC在面向对象编程中,是一种怎么的思想。
什么是DI?
相比于IoC,一种编程思想或者说指导性原则,DI讲的是一个更加具体的东西:依赖注入。
IOC或者DIP原则指导我们:通过面向抽象去编程,将控制权移交给依赖者、即抽象类的具体子实现类。这也意味着:获得依赖对象的过程被反转了!
- 构造器注入
- API注入、接口注入
- 注解注入
这是从表象观察上得出的结论,因为比较简单,不做示例代码。
- 分析了具体业务,注入的规则(选择具体的依赖对象)直接侵入,在编码中进行描述,包含在类的某一段业务逻辑的编写中。
- 注入过程抽象给第三方,使用者维护依赖规则。
我们重点讨论下这一块儿。
基类
注:我们仅用来做Demo说明问题,实际生产中绑定presenter的时机一般会更复杂一些。
就是最终在Activity中的这一段业务代码:
分析了具体业务,注入的规则(选择具体的依赖对象)直接侵入,在编码中进行描述,包含在类的某一段业务逻辑的编写中
- 一开始产品经理拍板,这个文档编辑应用就是单机的(不要问为什么,就是没多过脑子)
于是我们哼哧哼哧的完成了一个版本,数据都是存在本地数据库的。我们为各种XXXPresenter注入了各种XXXXDao的实例,当然,有些可能是单例。
- 项目上线后,用户对于创作交互好评如潮,但是提出反馈:没法分享和阅读他人开放的文章。产品经理一拍脑门,我怎么没想到,2.0:存储全部做服务端(不要问为什么之前做单机,就是没过脑子)
于是服务端的开始哼哧哼哧的搞。客户端开始哼哧哼哧的把之前所有注入XXXXDao的地方改成XXXXWebService,并且把之前自动存储的功能转嫁到WebService,不再存储本地DB。
- 项目上线后,IT和服务端主程开始天天盯着服务器监测,随后开始喷产品经理:”说了不信,所有功能都依靠服务器那是作死,QPS太高了“(不要问为什么产品经理之前不听,听了他也不懂,不见棺材不掉泪)
于是客户端的兄弟们又开始哼哧哼哧的修改,将注入的XXXXWebService修改成一种RepoImpl,它在内部封装了自动存储到DB,完成后提交到服务端,按照特定算法决定差异版本中实际有效的版本,并做本地和服务端同步。
- 终于项目又上线了,IT和后端主程可以睡安稳觉了。细心的用户又提出反馈了,我对文档编辑了,提交了之后、之前打开的详情页啊列表啊啥的信息都不同步啊,写文章的时候都挺费脑子的,一不注意就以为自己漏编辑了,又去操作一遍。产品经理又拍板了:应用内数据一致性维护
于是客户端程序员赶鸭子上架,EventBus满天飞,最终赶上了工期,但几个版本后,项目已经快无法维护了,尤其是大量直接操作DB使得体验变的越来越糟糕。
- 于是公司高薪聘请客户端架构师,试图最后锤死挣扎。
架构师放大招了,提出了本地中央仓储层,在内存对象层面实现多页面观测数据的一致性+基于数据变化的相应式设计,取代之前难以管理的EventBus事件体系、以及从DB读取数据同步页面。然后又带着大家做了一遍依赖的注入。并在总结会上提出了一个问题:“这几波依赖注入修改的爽吗?”
对于注入过程做抽象,用一个第三方,它抽象并实现了依赖的注入、接受使用者对依赖规则的维护,将整个系统中做依赖注入的内容剥离。
两种方式的区别
这里有必要直接给出结论了,假定这个系统是个10万行代码的项目,有100行代码是这样处理依赖注入的。
/ IoC和DI的发展史 /
- 1996年,Michael Mattson在一篇有关探讨面向对象框架的文章中,首先提出了IOC 的概念
- 2004年,Martin Fowler探讨了同一个问题,提出了IoC的实现细节,Martin Fowler的经典文章:《Inversion of Control Containers and the Dependency Injection pattern》(https://www.martinfowler.com/articles/injection.html)
- spring在实践中推广,2004年3月,Spring 1.0使用外部配置文件(xml)描述对象之间的依赖关系。
- 2004年10月,JDK1.5支持注解(Annotation)语法。2007年3月, Google发布 Guice 1.0,使用annotation描述依赖关系。
- 2007年11月,Spring 2.5支持使用annotation描述依赖关系
- 为了规范和统一,JCP于2009年10月发布了JSR330(https://jcp.org/en/jsr/detail?id=330)
- 2012年square发布了开源的dagger1,用于Android平台后来google接盘,搞了dagger2.
- @Inject
- @Qualifer, @Named
- @Scope, @Singleton
Inject :Identifies injectable constructors, methods, and fields. 需要注入的标识,可用于构造器(constructors), 方法(methods)或字段(fields)Qualifier:Identifies qualifier annotations. 限定器,多子类情况
Named:String-based qualifier. 使用字符串的限定符,
Scope:Identifies scope annotations. 标记作用域
Singleton:Identifies a type that the injector only instantiates once.
我们前面提到过,jsr-330是jcp为了规范各种提供给java生态中使用的ioc容器而定义的协议标准,在其他生态中,是不完全一致的,但是思想是一致的.
这篇文章写得内容很长,但精髓的内容并不是很多,主旨在于:(1)把复杂的概念通过最直白的语言讲透彻;(2)举出例子引发思考以达到和”被动接受的概念、结论“相互印证。
推荐阅读: 自撸一个Android IM库,即时通讯很难吗?
Shortcuts,让你可以在系统的桌面上为所欲为 由Android官方团队带你学习布局编辑器