依赖倒置原则

定义

依赖倒置?大家可能会觉得高深莫测。但是相信听我一翻解说之后,你就会恍然大悟,甚至你早已掌握到它的精髓了。我们先看一下依赖倒置原则的定义:

High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.(高层模块不应该依赖低层模块,它们都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象。)

意思就是说,无论是高层模块、低层模块还是细节,都应该依赖抽象,所以依赖倒置原则也可以理解为“依赖抽象原则”。那么,什么是依赖呢?假设我们有类A和类B,如果类A需要使用到类B(B是A的属性,或者A会调用到B的方法等),那么可以说类A依赖类B。那么什么又是抽象呢?抽象类、协议都属于抽象。所以,“依赖抽象”就是说当类A用到类B时,尽量引用类B的抽象类或者协议。把依赖倒置原则理解为依赖抽象原则更有助于理解。

大家可能会觉得奇怪,为什么说依赖抽象就是依赖倒置呢?因为在日常生活中,人们习惯于依赖于具体事务(细节),而不是抽象。比如说我们说开车就是具体的车,用电脑就是用具体的电脑。那么如果要倒过来去依赖抽象,就是依赖倒置。

那么为什么要依赖倒置呢?按照人们的直觉依赖正置(依赖具体事务)不好吗?下面就举个依赖正置的例子,来说明依赖正置的问题。

很简单,我们的任务是声明一个司机类和一个奔驰车类,然后让司机开车。我们按照我们现实生活的直觉来,两个类都是具体类,司机就是司机,奔驰车就是奔驰车,没有抽象类的存在。

宝马车类:

@interface BMWCar : NSObject
- (void)run;
@end@implementation BMWCar
- (void)run{NSLog(@"宝马车开动了");
}
@end

司机类:

#import "BMWCar.h"@interface Driver : NSObject
- (void)driveCar:(BMWCar *)car;
@end@implementation Driver
- (void)driveCar:(BMWCar *)car{[car run];
}
@end

这样就可以让我们的老司机老王开车了:

Driver *wang = [Driver new];
BMWCar *bmw = [BMWCar new];
[wang driveCar:bmw];

上面的代码好像没有什么问题。但是如果现在新增一辆奔驰车,我们的老司机老王却没办法开,因为他目前只有开宝马车的方法!如果要开奔驰车,可能需要为他新增开奔驰车的方法。那么如果现在又要新增特斯拉、奥迪、罗斯莱斯等车呢?难道要为每一辆新增的车去修改司机类?这显然是荒唐的。依赖于具体类,会导致类之间的耦合性太强,这就是在代码中依赖具体类的问题。

虽然说代码是现实世界的反映,但是代码和现实世界还是有所区别的,你需要“倒置”一下。解决上述问题的方法自然是依赖倒置,让司机依赖于抽象的车,而不是具体的车。

抽象车类:


 

@interface Car : NSObject
- (void)run;
@end@implementation Car
- (void)run{
}
@end

司机类(记得司机类现在依赖的是抽象的车类,而不是具体的车类):

#import "Car.h"@interface Driver : NSObject
- (void)driveCar:(Car *)car;
@end@implementation Driver
- (void)driveCar:(Car *)car{[car run];
}
@end

然后,就是我们的具体车类了。只要具体的车类继承自抽象车类,那么无论它是奔驰车,还是宝马车...我们的司机都可以开。

奔驰车:

@interface BenzCar : Car
@end@implementation BenzCar
- (void)run{NSLog(@"奔驰车开动了");
}
@end

让我们的老王开开奔驰:

Driver *wang = [Driver new];
Car *benz = [BenzCar new];
[wang driveCar:benz];

宝马车:

@interface BMWCar : Car
@end@implementation BenzCar
- (void)run{NSLog(@"宝马车开动了");
}
@end

让我们的老王也开开宝马:

Driver *wang = [Driver new];
Car *bmw = [BMWCar new];
[wang driveCar:bmw];

可见通过依赖倒置,现在无论新增多少种车,都不需要去修改司机类了。

优点

通过上面的例子,相信大家已经领略到在代码中使用依赖倒置原则的重要性了。总结一下依赖倒置原则的优点:

  1. 减少类之间的耦合;
  2. 降低并行开发引起的风险;
  3. 提高代码的可读性和可维护性。

关于上面第2点需要强调一下,依赖倒置对于并行开发非常重要,可以说是必不可少。因为在多个人一起进行开发的时候,如果没有抽象类或者接口,你要等到别人完成具体的类才能进行开发,那么谈何并行开发?相反我们只需要先定好抽象类或者接口,大家就能开工了。所以在并行开发的时候一定要遵守依赖倒置原则。

实践

到这里相信大家已经知道依赖倒置原则是怎么回事了。也许这你是第一次听说依赖倒置原则,但是你很可能听说过面向接口编程。面向接口编程是依赖倒置原则的最佳实践,如果你熟悉面向接口编程,那么恭喜你已经掌握了依赖倒置原则的精髓。

如果还是觉得抽象,下面列举一些具体的点,让大家可以有法可依:

  1. 每个类尽量都有接口或抽象类,或者两者具备。抽象是依赖倒置原则的基本要求;
  2. 变量的表面类型尽量是接口或者抽象类;
  3. 任何类都尽量不要从具体类派生。如果一个类是从具体类派生,那么这个类和它的非抽象的父类就形成强耦合;
  4. 尽量不要覆写基类的方法。如果基类是一个抽象类,而且这个方法已经实现了,子类尽量不要覆写。类间的依赖是抽象,覆写了抽象方法,会影响依赖的稳定性;
  5. 结合里氏替换原则使用。

注意

  1. 依赖倒置原则的优点很难在小项目中体现出来,在大型项目才能感受到它的重要性;
  2. 依赖倒置原则是6大设计原则中最难实现的;
  3. 有些情况还是需要依赖于细节。


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/432132.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

求一个连通图的割点(去掉一个点后图不再连通)

题目:求一个连通图的割点,割点的定义是,如果除去此节点和与其相关的边,图不再连通,描述算法。 分析: 1. 最简单也是最直接的算法是,删除一个点然后判断连通性,如果删除此点&#xff…

深入浅出 Java Concurrency (6): 锁机制 part 1[转]

前面的章节主要谈谈原子操作,至于与原子操作一些相关的问题或者说陷阱就放到最后的总结篇来整体说明。从这一章开始花少量的篇幅谈谈锁机制。 上一个章节中谈到了锁机制,并且针对于原子操作谈了一些相关的概念和设计思想。接下来的文章中,尽可…

行为树

行为树(Behavior Tree),有4大类型的Node: (1) Composites Node 组合节点,包括经典的:Sequence,Selector,Parallel * Selector Node 当执行本类型Node时,它将从begin到end迭代执行自己的Ch…

SCRUM 12.03

第二轮迭代从今天起正式开始了。12月3日,我们举行了一次组会。 第一轮迭代结束时,我们意识到第二轮迭代需要实现的功能主要如下: 在下次迭代的时候实现对多个网站的信息进行比较取最优惠的选择,目前我们劲针对了一个网站的信息进行…

阻止页面双击选中文本

轮播图实现中&#xff0c;发现当点击切换按钮时&#xff0c;如果用户点快乐&#xff0c;双击了按钮&#xff0c;就会选中文本。十分影响浏览效果&#xff0c;所以有了这篇文章。 IE以及谷歌下的解决办法&#xff1a; <div id"zell-carousel" class"zell-caro…

STL内嵌数据类型: value_type

使用stl库的时候一直对value_type这个东西理解的不是很好&#xff0c;可以说就是不理解。今天看了《STL源码剖析》才恍然大悟。这里稍作记录。 每个STL中的类都有value_type这种东西&#xff0c;通俗的说value_type 就是stl容器盛装的数据的数据类型&#xff0c;例如&#xff…

Boost.Python实现Python C/C++混合编程

导出函数 #include<string> #include<boost/python.hpp>using namespace std; using namespace boost::python;char const * greet() {return "hello,world";}BOOST_PYTHON_MODULE(hello_ext) {def("greet", greet); } import hello_ext pri…

swift UIActivityIndicatorView

// // ActivityIndicatorViewController.swift // UIControlDemo // // Created by on 14/12/1. // Copyright (c) 2014年 马大哈. All rights reserved. // import UIKit class ActivityIndicatorViewController: BaseViewController { var waitActivity:UIActivityIndi…

UE4打包后如何调试

在项目打包后发现有一个数组越界问题&#xff0c;然而无论是 Play in Editor或是 VS选为DebugGame后启动&#xff0c;游戏都没有任何问题&#xff0c;越界问题只在打包后出现。这里记录一下自己的Debug方法。 首先将项目以DebugGame配置打包&#xff1a; 更改打包配置&#xff…

asp.net 使用my97 datepicker实现前后两个日期的范围界定

说明&#xff1a;日期选择后&#xff0c;前面的日期小于等后面的日期&#xff0c;后面的日期大于等于前面的日期。点点看就知道了:) &#xff5e; 这里将周末日期不可选。代码如下&#xff1a; 1 <html xmlns"http://www.w3.org/1999/xhtml">2 <head runat…

james-2.3.2中的配置

james&#xff1a;1、解压缩2、先运行一遍3、修改配置 apps\james\SAR-INF\config.xml(1)postmaster(2)servername localhost --> abclocalhost j08.com --> abcj08.com 自动检查名称和IP设为false(3)注释掉RemoteAddrNotInNetwork(4)添加虚拟域名&#xff0c;指向localh…

Win7下安装配置gVim

本文根据vim官网的《Simple Steps to Help You Install gVim on Windows 7》【1】一文整理而成。 1. 下载gVim 在http://www.vim.org/download.php/pc 下找到“PC: MS-DOS and MS-Windows”&#xff0c;下载“gvim74.exe”【2】。 2. 安装gVim 1. 安装时可以选择更改目录&#…

ActiveReports 报表控件官方中文入门教程 (2)-创建、数据源、浏览以及发布

ActiveReports 报表控件官方中文入门教程 (2)-创建、数据源、浏览以及发布 原文:ActiveReports 报表控件官方中文入门教程 (2)-创建、数据源、浏览以及发布本篇文章将阐述首次使用 ActiveReports 报表控件 的方法&#xff0c;包括添加报表文件、绑定数据源以及如何发布报表等内…

C++ Lambda表达式基本用法

创建一个匿名函数并执行。采用的是配对的方括号[]。实例如下&#xff1a; 1 2 3 4 5 6 7 8 9 #include <iostream> using namespace std; int main() { []{ cout << "Hello,Worldn"; }(); } 我们也可以方便的将这个创建的匿名函数赋…

每日一测4(装箱与拆箱)

1、定义 装箱&#xff1a;用于在垃圾回收堆中存储值类型。装箱是值类型到 object 类型或到此值类型所实现的任何接口类型的隐式转换。 拆箱&#xff1a;从 object 类型到值类型或从接口类型到实现该接口的值类型的显式转换。 2、为什么要装箱&#xff1a; &#xff08;1&#x…

flex 正则表达式匹配规则

正则表达式扫描的优先级 1. 先根据空格&#xff0c;tab&#xff0c;回车分割字符串&#xff0c;作为正则表达式匹配的基础 2. 找到完全匹配的正则表达式&#xff0c;以排列在前面的优先级为高 3. 如果找不到匹配的表达式&#xff0c;那么从头开始截取字符串来查找合…

笔记本多硬盘win7下U盘安装Cnetos7引导问题!

CentOS7出来的时间已经不算短了&#xff0c;前段时间一直在虚拟机上使用&#xff0c;最近闲下来了&#xff0c;就像在自己的笔记本上装一个win7和Centos7的双系统体验以下实体机的效果&#xff0c;几经波折之后终于顺利的装上了WIN7和CentOS7的双系统&#xff01;在这里主要是想…

QString转char*的问题

QString tmp"abc"; char *p tmp.toLatin1().data()); QString tmp"abc"; char *p new char[1strlen(tmp.toLatin1().data())]; strcpy(p, tmp.toLatin1().data()); 运行模式两种方法都可以&#xff0c;调试模式&#xff0c;第一种方式无法得到QString的…

hdu 1870

水题。。。。 AC代码&#xff1a; #include <iostream> #include <queue> using namespace std; int main() {char str[1010];int i,k;while(scanf("%s",&str)!EOF){queue<char>q;for(i0;str[i]!B;i){if(str[i]()q.push(str[i]);if(str[i]))q.…