[Unity 设计模式]IOC依赖倒置
1.前言
最近在看《游戏开发与设计模式》一书,看到控制反转设计模式,作者说:上层模块不应该依赖于下层模块,上层模块和下层模块都应该依赖于接口,这样能减少耦合。然后附带举了个例子,我觉得特别好,就是一台计算机是属于上层模块,里面硬盘属于下层模块,计算机依赖于硬盘,硬盘是计算机的基本组成部件之一。这里提到依赖一词,下面就详细谈谈依赖。
2.依赖
依赖就是一种联系关系,人对人的依赖那是一种羁绊关系。再拿上面的计算机举例,华硕是我们都耳熟能详的计算机厂商,西部数据和希捷都是硬盘厂商,如果说华硕依赖于某一个具体型号的硬盘,那么华硕同一款型号的电脑那得生产多少台内置硬盘不同的型号的电脑。假设华硕厂商喜欢用西部数据的硬盘,那好假如西部数据倒闭或者硬盘升级,那么华硕厂商是不是会造成连锁反应,华硕已经生产的电脑要重新回炉重造或者说要被迫改成使用其他希捷厂商的电脑。造成这种问题的原因就是华硕对西部数据有严重的依赖关系,解决方法就是硬盘厂商生产硬盘的时候遵循硬盘接口SATA接口协议,然后计算机厂商也遵循这种接口协议,这就是我们看到的PC具有好多接口例如我们熟知的USB接口,USB是更通用的接口,无论鼠标、键盘还是优盘都具备这样的接口,所以只要遵循USB接口或者ASTA接口的设备都能用用在任何一个PC计算机上。我们如果写代码的话,也能这样设计我们的代码模块,那么模块跟模块之间耦合度就很低了。下面我们来看一个简单的例子:
public class FlashDisk
{
public string TypeName { get; set; }
public void TransportData()
{
Console.WriteLine(string.Format("读取{0}硬盘的数据"));
} public FlashDisk(string name)
{
TypeName = name;
}
} public class HardDisk
{
public string TypeName { get; set; }
public void TransportData()
{
Console.WriteLine(string.Format("读取{0}硬盘的数据"));
} public HardDisk(string name)
{
TypeName = name;
}
}
public class Computer
{
public Computer(string name)
{
TypeName = name;
}
public void ReadHardDiskData(HardDisk m_HardDisk)
{
m_HardDisk.TransportData();
} public void ReadFlashDiskData(FlashDisk m_FlashDisk)
{
m_FlashDisk.TransportData();
}
}
static void ReadData()
{
HardDisk hardDisk = new HardDisk("西部数据");
FlashDisk flashDisk = new FlashDisk("闪迪");
Computer pc = new Computer("联想");
pc.ReadHardDiskData(hardDisk);
pc.ReadFlashDiskData(flashDisk);
}
上面是一个简单的示例,想要实现传输数据的功能,用户的操作一个PC来读取某个硬盘或者优盘才能实现。先看看依赖关系:
- Computer依赖HardWare
- ReadData操作依赖Computer
- ReadData操作依赖HardDisk/FlashDisk
3.依赖倒置
如果我们这时候用不用的电脑比如联想来读取金斯顿优盘的数据,我们就要抽象出来减少耦合。
耦合就是依赖,如果依赖过于严重就会牵一发而动全身,所谓城门失火,殃及池鱼。依赖关系越少,维护就越容易,所以必须要减少依赖。
幸亏Robert Martin提出面向对象设计原则-依赖倒置原则:
- 上层模块不应该依赖于下层模块,他们共同依赖于一个抽象。
- 抽象不依赖于具体,具体依赖于抽象。
理解:
- 上层模块就是使用者,这里的PC使用优盘、硬盘,而后者自然就是被使用者就是下层模块。他们应该都共同依赖于抽象——接口。
- 面向对象编程时需要面向抽象或者面向接口编程,抽象或者接口一般比较稳定,接口不要依赖于具体的对象。
根据控制反转的原则我们来重新设计上的实现:
- 优盘或者硬盘都要遵循一个接口协议,这里我们就定义ISATA和IUSB协议,
- 数据传输接口ISATA和IUSB都要遵循数据传输协议我们就定义ITransportData
- ReadData操作依赖PC,就让ReadData和HardDisk/FlashDisk都依赖ISATA和IUSB协议,于是优化过的代码就出来了
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine; public interface ITransportData
{
void TransPortData();
} public interface IUSB : ITransportData
{
string TypenName { get; set; }
} public interface ISATA : ITransportData
{
string TypenName { get; set; }
} public class UFlashDisk : IUSB
{
public string TypenName { get; set; } public UFlashDisk(string typeName)
{
TypenName = typeName;
}
public void TransPortData()
{
UnityEngine.Debug.Log(string.Format("优盘型号:{0}传输数据", TypenName));
}
} public class HardDisk : ISATA
{
public string TypenName { get; set; } public HardDisk(string typeName)
{
TypenName = typeName;
} public void TransPortData()
{
UnityEngine.Debug.Log(string.Format("硬盘型号:{0}传输数据", TypenName));
}
} public class Computer
{
ISATA m_HardDisk; public void SetHardWare(ISATA hardDisk)
{
m_HardDisk = hardDisk;
} public void ReadData()
{
if (m_HardDisk == null)
throw new Exception();
m_HardDisk.TransPortData();
} public void UseUFlashDisk(IUSB flashDisk)
{
flashDisk.TransPortData();
}
} public class IOCDemo : MonoBehaviour
{
void Start()
{
ISATA hardDisk = new HardDisk("西部数据硬盘");
IUSB uFlashDisk = new UFlashDisk("闪迪优盘");
var pc = new Computer();
pc.SetHardWare(hardDisk);
pc.ReadData();
pc.UseUFlashDisk(uFlashDisk);
pc.UseUFlashDisk(new UFlashDisk("西门子优盘"));
}
}
4.控制反转(IOC)
现实生活中,我们想要读取数据,无论我们用什么电脑,文件数据在哪个优盘里,这都取决于我们用户自己。
上面基本实现了隔离,具体的电脑跟优盘隔离,具体的优盘、硬盘跟接口有关系,如果我们对象在代码里面写死,假如就用华硕电脑读取闪迪优盘,这样又不灵活了,如果需求是我用联想电脑去读取金斯顿优盘,我们是不是又要改代码。这样我们就可以把决定权交给我们配置的人,游戏开发中这类人就称之为策划,我们就把权利给他们,让他们想用什么电脑读取什么优盘就让他们来配表实现,然后程序写一个读表生成具体对象的读取数据的操作。
这样控制权交给了配表的文件,这种就是我们这里要说的控制反转。
public class Computer
{
public string Name { get; set; }
public Computer(string name)
{
Name = name;
} ISATA m_HardDisk; public void SetHardWare(ISATA hardDisk)
{
m_HardDisk = hardDisk;
} public void ReadData()
{
if (m_HardDisk == null)
throw new Exception();
m_HardDisk.TransPortData();
} public void UseUFlashDisk(IUSB flashDisk)
{
flashDisk.TransPortData();
}
} var pc = new Computer(“读取配置表”);
pc.SetHardWare(new UFlashDisk(“读取配置表”));
pc.ReadData();
控制反转IOC是Inversion of control的缩写,说将对象进行转移,转移到第三方,比如交给了配表文件。它就像一个对象创建工程,想要什么对象就配置什么对象,这样原先的依赖关系没有了,都变成IOC容器依赖了。
5.依赖注入(ID)
上面说的控制反转是一个思想概念,要看具体的实现,配表也是一种实现方式。依赖注入提出了具体的思想。
依赖注入DI是Dependency Injection缩写,它提出了“哪些东东的控制权被反转了,被转移了?”,它也给出了答案:“依赖对象的创建获得被反转”。
所谓依赖注入,就是由IoC容器在运行期间,动态地将某种依赖关系注入到对象之中。
上面SetHardWare其实就是运行时候依赖注入,将具体的依赖对象传递进去,传递的切入点可以是方法,可以是属性,可以是构造函数。
6.小结
通过一个小例子来由浅入深讲解IOC模式,看完之后记得自己在敲一遍哦,这样感悟才深刻!
7.工程下载
https://git.oschina.net/dingxiaowei/UnityIOC.git
8.相关设计模式好文连接
[Unity 设计模式]IOC依赖倒置的更多相关文章
- 北风设计模式课程---依赖倒置原则(Dependency Inversion Principle)
北风设计模式课程---依赖倒置原则(Dependency Inversion Principle) 一.总结 一句话总结: 面向对象技术的根基:依赖倒置原则(Dependency Inversion ...
- ASP.NET 设计模式中依赖倒置原则
依赖倒置原则 A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象. B.抽象不应该依赖于具体,具体应该依赖于抽象. 依赖倒置原则 A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于 ...
- Unity Ioc 依赖倒置及Untity AOP被动拦截/自动拦截
各位博友金安,首先声明这是一篇转载的博客,原文链接:https://www.cnblogs.com/scottpei/archive/2013/01/08/2851087.html 十年河东,十年河西 ...
- C#软件设计——小话设计模式原则之:依赖倒置原则DIP
前言:很久之前就想动笔总结下关于软件设计的一些原则,或者说是设计模式的一些原则,奈何被各种bootstrap组件所吸引,一直抽不开身.群里面有朋友问博主是否改行做前端了,呵呵,其实博主是想做“全战”, ...
- IoC模式(依赖、依赖倒置、依赖注入、控制反转)
1.依赖 依赖就是有联系,有地方使用到它就是有依赖它,一个系统不可能完全避免依赖.如果你的一个类或者模块在项目中没有用到它,恭喜你,可以从项目中剔除它或者排除它了,因为没有一个地方会依赖它.下面看一个 ...
- 对依赖倒置原则(DIP)及Ioc、DI、Ioc容器的一些理解
1.概述 所谓依赖倒置原则(Dependence Inversion Principle)就是要依赖于抽象,不要依赖于具体.简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模 ...
- 对依赖倒置原则(DIP)及Ioc、DI、Ioc容器的一些理解(转)
所谓依赖倒置原则(Dependence Inversion Principle)就是要依赖于抽象,不要依赖于具体.简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合 ...
- 个人对【依赖倒置(DIP)】、【控制反转(IOC)】、【依赖注入(DI)】浅显理解
一.依赖倒置(Dependency Inversion Principle) 依赖倒置是面向对象设计领域的一种软件设计原则.(其他的设计原则还有:单一职责原则.开放封闭原则.里式替换原则.接口分离原则 ...
- 【转载】浅析依赖倒置(DIP)、控制反转(IOC)和依赖注入(DI)
原文地址 http://blog.csdn.net/briblue/article/details/75093382 写这篇文章的原因是这两天在编写关于 Dagger2 主题的博文时,花了大量的精力来 ...
随机推荐
- 通过Maven将指定Jar包下载到指定的本地目录
现在大家大部分都通过Maven等工具来管理包,但是特殊情况下还是需要将包下载到本地.我们可以通过maven命令来完成这个需求.创建一个pom.xml文件,文件内容如下: <?xml versio ...
- MySql(四)Select条件查询
select条件查询的格式如下: SELECT 查询列表FROM 表名WHERE 筛选条件:123456根据筛选条件可以分为以下几类: 按照条件按表达式进行筛选 常用条件运算符如下:> .< ...
- 00JAVA EE
JAVA EE 三层架构 我们的开发架构一般都是基于两种形式,一种是C/S架构,也就是客户端/服务器,另一种是B/S架构,也就是浏览器服务器.在JavaEE开发中,几乎全都是基于B/S架构的开发.那么 ...
- ie6,ie7,ie8,FF 浏览器兼容问题
javascript部分 1. document.form.item 问题问题:代码中存在 document.formName.item("itemName") 这样的语句,不能在 ...
- P1091 合唱队形题解(洛谷,动态规划LIS,单调队列)
先上题目 P1091 合唱队形(点击打开题目) 题目解读: 1.由T1<...<Ti和Ti>Ti+1>…>TK可以看出这题涉及最长上升子序列和最长下降子序列 2 ...
- UVA - 1608 Non-boring sequences(分治法)
题目: 如果一个序列的任意连续的子序列中至少有一个只出现一次的元素,则称这个序列是不无聊的.输入一个n(n≤200000)个元素的序列A(各个元素均为109以内的非负整数),判断它是不是不无聊的. 思 ...
- 团队一致性的PHP开发环境之Vagrant
Vagrant 简介 Vagrant是一个基于Ruby的工具,用于创建和部署虚拟化开发环境. 它的主要意义是让所有开发人员都使用和线上服务器一样的环境,本质上和你新建一个虚拟机 安装 # https: ...
- CCF201709-1 打酱油 java(100分)
试题编号: 201709-1 试题名称: 打酱油 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 小明带着N元钱去买酱油.酱油10块钱一瓶,商家进行促销,每买3瓶送1瓶,或者每 ...
- 解决Python打包exe控制台无法粘贴问题
使用pyinstaller打包生成可执行exe文件后,发现启用input()接受键盘输入时窗口无法粘贴也无法右键,找了好久终于找到问题所在: 一是通过右键单击控制台主题边框在弹出的菜单中选择编辑.粘贴 ...
- IIS部署网站只有首页能访问,其他链接失效/运行.net+Access网站-可能原因:IIS未启用32位应用程序模式
在64位的机子上IIS运行32位的.NET程序 由于64位操作系统不支持Microsoft OLE DB Provider for Jet驱动程 也不支持更早的Microsoft Access Dri ...