连载:面向对象葵花宝典:思想、技巧与实践(34) - DIP原则

简介:

DIP,dependency inversion principle,中文翻译为“依赖倒置原则”。

 

DIP是大名鼎鼎的Martin大师提出来的,他在1996 5月的C++ Reporter发表“ The Dependency Inversion Principle”的文章详细阐述了DIP原则,并且在他的经典著作《 Agile Software Development, Principles, Patterns》(中文翻译为:敏捷软件开发:原则、模式与实践)、《Practices, and Agile Principles, Patterns, and Practices in C#》(中文翻译为:敏捷软件开发:原则、模式与实践(C#版))中详细解释了DIP原则。

 

DIP原则主要有两点含义:

1) 高层模块不应该直接依赖低层模块,两者都应该依赖抽象层;

2) 抽象不能依赖细节,细节必须依赖抽象;

 

虽然DIP原则的解释非常清楚,但要真正理解也不那么简单,因为有几个关键的术语都比较抽象,我们需要更详细的解析:

1)什么是模块?

英文中用到了module、component,但我们这是在讲类的设计原则,为什么要把DIP拉进来呢?

其实Martin大师只是讲一个设计原则而已,这个原则可以应用到软件系统不同的层级。

例如:站在架构层的角度,模块可以指子系统subsystem

站在子系统的角度,模块可以指module,component

站在模块的角度:模块可以指类

所以说,这里的模块应该是一个广义的概念,而不是狭义的软件系统里各个子模块。

 

2)什么是依赖?

这里的依赖对应到具体的面向对象领域其实包含几个内容:

高层模块“依赖”低层模块:指高层模块需要调用低层模块的方法;

高层模块依赖抽象层:指高层模块基于抽象层编程;

低层模块依赖抽象层:指低层模块继承(inheritance)或者实现(implementation)抽象层;

细节依赖抽象:其实和上一个依赖是同一个意思;


所以说,大师就是大师啊,一个简简单单的“依赖”将各种情况都概括进来了,只是苦了我们这些平凡人,要么导致无法理解,要么导致理解错误:(

 

我们以一个简单样例来详细解释这些依赖,样例包含一个Player类,代表玩家;ICar接口,代表汽车;Benz、Ford、Chery代表具体的汽车,详细的代码如下

Player

package com.oo.oop.dip;

/**
 * 玩家,对应DIP中的“高层模块” 
 *
 */
public class Player {

	/**
	 * 开福特
	 * 不好的依赖:对应DIP中的“高层模块依赖低层模块”,Player直接使用了Ford类对象作为参数,Ford类修改,Player类【需要】重新编译测试
	 */
	public void play(Ford car)
	{
		car.accelerate();
		car.shift();
		car.steer();
		car.brake();
	}
	
	/**
	 * 开奔驰
	 * 不好的依赖:对应DIP中的“高层模块依赖低层模块”,Player直接使用了Benz类对象作为参数,Benz类修改,Player类【需要】重新编译测试
	 */
	public void play(Benz car)
	{
		car.accelerate();
		car.shift();
		car.steer();
		car.brake();
	}
	
	/**
	 * 开奇瑞
	 * 不好的依赖:对应DIP中的“高层模块依赖低层模块”,Player直接使用了Chery类对象作为参数,Chery类修改,Player类【需要】重新编译测试
	 */
	public void play(Chery car)
	{
		car.accelerate();
		car.shift();
		car.steer();
		car.brake();
	}
	
	/**
	 * 开车
	 * 好的依赖: 对应DIP中的“高层模块依赖抽象层”,Player依赖ICar接口,不需要知道具体的车类型,Ford、Benz、Chery类修改,Player类【不需要】重新编译测试,只有ICar修改的时候Player才需要修改
	 */
	public void play(ICar car)
	{
		car.accelerate();
		car.shift();
		car.steer();
		car.brake();
	}

}

ICar

package com.oo.oop.dip;

/**
 * 汽车接口,对应DIP中的抽象层
 */
public interface ICar {

	/**
	 * 加速
	 */
	public void accelerate();
	
	/**
	 * 换挡
	 */
	public void shift();
	
	/**
	 * 转向
	 */
	public void steer();
	
	/**
	 * 刹车
	 */
	public void brake();
}

Benz

package com.oo.oop.dip;

/**
 * 奔驰,实现了ICar接口,对应DIP中的“低层依赖抽象层” 
 *
 */
public class Benz implements ICar {

	@Override
	public void accelerate() {
		
		//加速非常快
		System.out.println("Benz accelerate: very fast !!"); 
	}

	@Override
	public void shift() {
		
		//自动挡
		System.out.println("Benz shift:  automatic transmission !!"); 
	}

	@Override
	public void steer() {

		//非常平稳
		System.out.println("Benz steer:  very smooth,ESP && DSC && VSC !!"); 
	}

	@Override
	public void brake() {
		
		//刹车辅助系统
		System.out.println("Benz steer:  ABS && EBA && BAS && BA !!"); 
	}

}

Ford

package com.oo.oop.dip;

/**
 * 福特,实现了ICar接口,对应DIP中的“低层依赖抽象层” 
 *
 */
public class Ford implements ICar {

	@Override
	public void accelerate() {
		
		//加速快
		System.out.println("Ford accelerate: fast !!"); 
	}

	@Override
	public void shift() {
		
		//手自一体变速器
		System.out.println("Ford shift:  Tiptronic transmission !!"); 
	}

	@Override
	public void steer() {

		//平稳
		System.out.println("Ford steer:  smooth,ESP !!"); 
	}

	@Override
	public void brake() {

		//刹车辅助系统
		System.out.println("Ford steer:  ABS && EBA &!!"); 
	}

}

Chery

package com.oo.oop.dip;

/**
 * 奇瑞,实现了ICar接口,对应DIP中的“低层依赖抽象层” 
 *
 */
public class Chery implements ICar {

	@Override
	public void accelerate() {
		
		//加速慢
		System.out.println("Chery accelerate: slow !!"); 
	}

	@Override
	public void shift() {
		
		//手动挡
		System.out.println("Chery shift:  manual transmission !!"); 
	}

	@Override
	public void steer() {

		//平稳
		System.out.println("Chery steer:  smooth,ESP && DSC !!"); 
	}

	@Override
	public void brake() {
		
		//刹车辅助系统
		System.out.println("Chery steer:  only ABS !!"); 
	}

}


================================================ 

转载请注明出处:http://blog.csdn.net/yunhua_lee/article/details/30749311
================================================ 


相关文章
|
存储 对象存储 Python
`openpyxl`是一个用于读写Excel 2010 xlsx/xlsm/xltx/xltm文件的Python库。它不需要Microsoft Excel,也不需要.NET或COM组件。
`openpyxl`是一个用于读写Excel 2010 xlsx/xlsm/xltx/xltm文件的Python库。它不需要Microsoft Excel,也不需要.NET或COM组件。
|
数据采集 存储 人工智能
cdga|数据治理:应对核心业务数据质量参差不齐的挑战与策略
数据治理是指通过制定并实施一系列政策、流程和技术手段,确保数据的可用性、完整性、准确性和安全性,以支持企业的决策和业务运营。对于核心业务数据质量参差不齐的问题,数据治理的重要性不言而喻
|
供应链 监控 算法
ERP系统中的库存优化与成本控制解析
【7月更文挑战第25天】 ERP系统中的库存优化与成本控制解析
1229 2
|
SQL 存储 数据管理
掌握SQL Server Integration Services (SSIS)精髓:从零开始构建自动化数据提取、转换与加载(ETL)流程,实现高效数据迁移与集成——轻松上手SSIS打造企业级数据管理利器
【8月更文挑战第31天】SQL Server Integration Services (SSIS) 是 Microsoft 提供的企业级数据集成平台,用于高效完成数据提取、转换和加载(ETL)任务。本文通过简单示例介绍 SSIS 的基本使用方法,包括创建数据包、配置数据源与目标以及自动化执行流程。首先确保安装了 SQL Server Data Tools (SSDT),然后在 Visual Studio 中创建新的 SSIS 项目,通过添加控制流和数据流组件,实现从 CSV 文件到 SQL Server 数据库的数据迁移。
3789 0
|
人工智能 算法 大数据
【Python初级人工智能精讲】用Paddlehub给一段没有标点符号的文字加上合适的标点符号
今天给分享的程序是:给一段文字自动加上合适的标点符号,使用的是飞桨的AI算法模型:auto_punc,可以智能的分析文字中的情感并在每段文字中加上适合的标点符号。
【Python初级人工智能精讲】用Paddlehub给一段没有标点符号的文字加上合适的标点符号
|
Ubuntu 关系型数据库 MySQL
解决方案:MySQL数据表明明存在,但是就是报错表不存在,原来是需要配置 MySQL 忽略表名大小写!
解决方案:MySQL数据表明明存在,但是就是报错表不存在,原来是需要配置 MySQL 忽略表名大小写!
1249 0
|
存储 SQL Oracle
细说MySQL锁机制:S锁、X锁、意向锁...
好久没有深入地写文章了,这次来发一篇,通过mysql事物 | Joseph's Blog (gitee.io)和其他一些博客有感进行一些补充,InnoDB详解在下期发布 加锁机制 乐观锁和悲观锁 之前在JVM中其实也讲到,JVM在对象初始化的过程中其实也是使用的乐观锁
873 0
细说MySQL锁机制:S锁、X锁、意向锁...
|
存储 网络协议 安全
IPsec ESP 数据包的 UDP 封装
选择共享 IKE 和 UDP 封装的 ESP 流量的端口号是因为它提供了更好的扩展性(NAT 中只有一个 NAT 映射;无需发送单独的 IKE keepalive)、更容易配置(仅在防火墙中配置一个端口),更容易实现。
1944 0
IPsec ESP 数据包的 UDP 封装
|
机器学习/深度学习 存储 文字识别
深度学习经典网络解析图像分类篇(一):LeNet-5
LeNet-5,这篇是由LeCun和Bengio在1998年撰写的论文(LeCun和Bengio和Hitton成被称为深度学习三巨头,在2018年一起获得图灵奖)。
800 0
|
JSON 安全 关系型数据库
PostgreSQL的优势:为何它成为主流数据库管理系统
PostgreSQL的优势:为何它成为主流数据库管理系统
4114 0