当前位置: 首页 > 编程日记 > 正文

从高耦合到低耦合到底有多远?

一切都是拥抱变化,反过来说,如果没有变化或者需求很稳定,那么一切就是过度设计。所以,一切都要看情况,回到了马克思主义的辩证学。呵呵。

无论书还是博客, 耦合这个词已被无数人说烂,任何一位程序员都会告诉你设计软件要注意低耦合,可究竟什么是低耦合?每次去查这个问题,就会牵扯出各种术语和理论,让人头晕。最近看了一些英文资料,发现低耦合其实没那么复杂。

什么是耦合?怎样的代码叫高耦合?

“耦合”翻译自英文(coupling),英文描述是:"when a component has a dependency on something else". 这句话简单易懂--当一个组件对其他东西有依赖就叫耦合,为方便描述,先给段代码:

public class EmailService
{public void SendMessage() { }
}public class NotificationSystem
{private EmailService svc; public NotificationSystem() { svc = new EmailService(); } public void InterestingEventHappend() { svc.SendMessage(); } }

代码的逻辑很简单:NotificationSystem通过内置的EmailService类发送邮件,即NotificationSystem的功能依赖EmailService类。我相信应有不少人对代码感觉亲切,我参与过的项目基本都这种风格,可惜这就是高耦合的设计。

高耦合翻译自“tightly coupled”,描述是这样的:"A class that knows a lot about the other classes it interacts with is said to be tightly coupled".翻译过来就是---它知道的太多了。^_^

最快的解耦方式

为了让它知道的不那么多,现在贴一份改良后的代码:

public interface IMessageService {void SendMessage();}public class EmailService : IMessageService { public void SendMessage() { } } public class NotificationSystem { private IMessageService svc; public NotificationSystem() { svc = new EmailService(); } public void InterestingEventHappend() { svc.SendMessage(); } }

与之前比较,svc变量类型变成了接口IMessageService ,从而使NotificationSystem依赖IMessageService接口,而不是EmailService类。 但svc通过new 方式赋值,这让两个类藕断丝连,一旦EmailService变化,NotificationSystem也跟着变,违背了开闭原则。

通过控制反转彻底解耦

想彻底解耦,就要换一种方式对svc赋值,于是想到控制反转模式,控制反转翻译自“inversion of control”简称Ioc,一句话描述:“Moving the creation of dependencies outside of the class that consumes those dependencies”,简单翻译过来就是:在外面创建这个类。

现在我们先抽象一个接口用于“外部创建”。

public interface IMessageService {void SendMessage();}public class EmailService : IMessageService { public void SendMessage() { } } public interface IServiceLocator { IMessageService GetMessageService(); } public class NotificationSystem { private IMessageService svc; public NotificationSystem(IServiceLocator locator) { svc = locator.GetMessageService(); } public void InterestingEventHappend() { svc.SendMessage(); } }

从代码看出,现在svc是通过IServiceLocator接口类创建,从而让原类之间解耦。IServiceLocator的实现类就像工厂模式,通过参数或配置文件等决定生成哪个类。然而这种做法让IServiceLocator和IMessageService 的实现类之间增加了耦合,每添加一个IMessageService 的实现类,就要修改IServiceLocator的代码,可能是switch或连续的if,这样看似不错的模式仍然违反开闭原则:

public class ServiceLocator:IServiceLocator{public IMessageService GetMessageService(){string type = "type1"; switch (type) { case "type1":return new EmailService1(); case "type2": return new EmailService2(); case "type3": return new EmailService3(); ………… } } }

用Ioc容器完成高耦合到低耦合的蜕变

完全蜕变,就要求助于依赖注入了,这个词和控制反转是好基友,一般都同时出现。实际开发中,我们往往使用IoC容器来实现依赖注入的需求。通过Ioc容器(以Autofac为例)改善代码如下:

public class NotificationSystem{private IMessageService svc;public NotificationSystem(IMessageService messageService) { svc = messageService; } public void InterestingEventHappend() { svc.SendMessage(); } }

可以看到NotificationSystem的构造函数直接传入IMessageService接口变量做参数。在全局类的代码如下:

var builder = new ContainerBuilder();builder.RegisterType<EmailService>().As<IMessageService>();

通过依赖注入来实例化NotificationSystem类:

IMessageService messageService= container.Resolve<IMessageService>();
   NotificationSystem system=new NotificationSystem(messageService);

借助Ioc的帮助,当IMessageService添加新的实现类时,也不用修改其他类的内部代码,在配置代码中,仅修改类名便可实现功能的切换。

结语

现在很多的开源代码都是这种模式,类内部依赖接口,通过Ioc容器灵活配置,熟悉了这种模式,有助于理解别人的设计意图,我也从中收益良多。但也有让我不爽的地方就是看别人的代码时,每次用F12跟踪源码,都会跳转到描述接口的代码文件中,想看具体实现总要害我找半天。

参考资料:<Professional Asp.Net MVC 3>

相关文章:

写论文查论文查参考文献

知网翻译助手&#xff1a;网页知网翻译助手 百度学术&#xff1a;百度学术—导出参考文献 IEEE&#xff1a;IEEE 添加上标&#xff1a;如下图 添加后&#xff0c;如下图&#xff1a; 添加完成&#xff01; WPS软件里面的公式编辑器添加空格为CtrlAltSpace即可&#xff01; …

C# Unity编程终极指南

使用现代Unity开发技术创建一个有趣的2D平台&#xff0c;掌握Unity引擎和C#编程 你会学到: 学习C#的基础知识。从变量、“如果”语句到创建面向对象的结构。没有编程经验是必要的。 创建一个可玩的角色(征服者)&#xff0c;具有动画&#xff0c;向任何方向移动&#xff0c;跳跃…

咪咕盒子链接服务器失败_云服务器怎样备份数据库备份

云服务器怎样备份数据库备份&#xff1f;云服务器数据库的备份很重要&#xff0c;而手动操作会比较麻烦。以西部数码云服务器为例&#xff0c;可以实现 Ms Sqlserver数据库定时自动备份&#xff0c;并存至指定存储空间。打开链接 下载&#xff0c;下载后无需安装&#xff0c;点…

在Ubuntu下构建Bullet以及执行Bullet的样例程序

在Ubuntu下构建Bullet以及执行Bullet的样例程序1、找到Bullet的下载页&#xff0c;地址是&#xff1a;https://code.google.com/p/bullet/downloads/list2、下载Bullet。找到.tgz格式进行下载。我下载的版本号是bullet-2.82-r2704。 3、假设没有安装cmake&#xff0c;那么使用s…

2022-2028年中国第五代移动通信技术(5G)市场研究及前瞻分析报告

【报告类型】产业研究 【报告价格】4500起 【出版时间】即时更新&#xff08;交付时间约3个工作日&#xff09; 【发布机构】智研瞻产业研究院 【报告格式】PDF版 本报告介绍了中国第五代移动通信技术&#xff08;5G&#xff09;行业市场行业相关概述、中国第五代移动通信…

机房合作—我是组长

五一期间开始机房合作&#xff0c;到现在一个多星期了。我&#xff0c;蕾蕾&#xff0c;亮亮一组&#xff0c;我担任组长一职。在着手准备项目开始之前&#xff0c;我们听取了各位师父的一些建议&#xff0c;也算是给我们指明一下方向。第一天晚上&#xff0c;我召开了我们项目…

Linux环境下命令行截图【转】

参考链接&#xff1a;命令行截图 将剪切板内容粘贴出来&#xff1a;CtrlV

用Unity和Playmaker创建一个限时游戏 Creating a Time Limit game with Unity and Playmaker

本课程结束时&#xff0c;您将拥有在Unity中使用Playmaker创建游戏的工具 你会学到: playmaker状态的基础以及它们如何与动作一起工作。 安装悬停车&#xff0c;可以在竞技场内行驶。 不同力度的射击地雷驱动中心机。 设置坏地雷和电源盒。 设置主时光机机制。 影响时间机器的…

app.vue 跳转页面_独立站如何提高产品页面转化呢?

在网上商城中&#xff0c;你的产品页面也是销售页面。顾客进入产品页面&#xff0c;然后根据你提供的产品描述内容&#xff0c;再决定是否立马购买&#xff0c;或者以后再考虑购买。以下是小跨收集的可以用于提高你独立站产品描述页面转化的几个要素。1.撰写激动人心的产品标题…

原生javascript实现放大镜效果

2019独角兽企业重金招聘Python工程师标准>>> html部分&#xff1a; <div class"main"><div id"xiaotu" class"xiaotu"><img src"http://zhangyan520.com/1.jpg" alt"" /><div id"yido…

新建个人博客参考

各种配置过程&#xff1a;新建参考 如果输入链接&#xff0c;出现如下截图&#xff0c;参考&#xff1a;报错404

C4D+ PS打造城市场景 Create a Cityscape with Cinema 4D + Photoshop

初级到中级课程&#xff0c;包括创建真实的城市景观可视化的步骤 你会学到: 建筑三维建模所涉及的创造性和技术性步骤。 使用变形器和MoGraph克隆器创建建筑变体&#xff0c;以更改每个建筑的形状。 创建城市街区&#xff0c;添加环境和提高中央处理器性能的技巧。 使用Adobe …

抽象工厂————三层架构

抽象工厂作用:降低BLL和Model层耦合度 核心思想:1.通过接口类实现对象的分离 2.通过一个类&#xff0c;实现指定对象的创建&#xff0c;并且这个类通过配置文件决定获取哪个对象 这样只要调用一个接口和这个类&#xff0c;就能实现BLL和Model的分离 这样做的优点是便于维护和…

jQuery 一次定时器_干货 | 小论定时器玩法(时间轮询法)

EEWORLD电子资讯 犀利解读 技术干货 每日更新经常来说&#xff0c;对于一些不复杂的单片机应用&#xff0c;而且对于内存和存储要求比较严格&#xff0c;又需要多分时去处理一些指定的任务&#xff0c;在无法使用RTOS的情况下&#xff0c;使用一个硬件定时器&#xff0c;来建立…

第一次团队冲刺2

今天在自己电脑上搭建了webservice&#xff0c;学习了很多关于webservice的知识&#xff0c;但还有很多不懂的。 还没有做好连接&#xff0c;其他的如查询等也没做。转载于:https://www.cnblogs.com/318abc/p/4504085.html

基于四元数互补滤波的无人机姿态解算

导航坐标系为东北天&#xff08;ENU&#xff09;&#xff0c;其与机体坐标系&#xff08;b&#xff09;的方向余弦矩阵为CbcC_{b}^{c}Cbc​

Unity粒子系统创建VFX游戏特效学习教程 Visual Effects in Unity Particle Systems [Beginner’s Guide]

在Unity中学习高级粒子系统和视觉效果创建。初级到中级 你会学到: 游戏的视觉效果 Unity粒子系统 Unity中的Vfx 创建Unity视觉效果的初级到中级指南 课程获取&#xff1a;Unity粒子系统创建VFX游戏特效学习教程-云桥网 MP4 |视频:h264&#xff0c;1280720 |音频:AAC&#xf…

gulp 配置自动化前端开发

有的人说&#xff0c;grunt已经廉颇老矣&#xff0c;尚能饭否。gulp已经成为了未来的趋势&#xff0c;或许将撼动grunt的地位。 那么就得看看gulp到底优势在哪里&#xff0c;在我最近的使用中发现&#xff0c;我的到了一个结论&#xff1a;“grunt廉颇老矣...”。 gulp是基于流…

iphone相册怎么加密_iphone相册加密码锁,保护隐私

在以往很多使用iphone的小伙伴都会遇到一个难题&#xff0c;在不越狱的情况下进行给相册进行设置密码锁&#xff0c;这是一个无法完成的目标&#xff0c;在前几期也为大家分享了相册照片加密方法&#xff0c;但是用起来很是不方便&#xff0c;今天就为大家分享利用时间限额达到…

redis 常用配置

1. Redis默认不是以守护进程的方式运行&#xff0c;可以通过该配置项修改&#xff0c;使用yes启用守护进程 daemonize no 2. 当Redis以守护进程方式运行时&#xff0c;Redis默认会把pid写入/var/run/redis.pid文件&#xff0c;可以通过pidfile指定 pidfile /var/run/redis.pid …

hexo定制个人博客matery主体打开公式渲染

在主体的_config文件里面将enable调整为true mathjax:enable: truecdn: https://cdn.bootcss.com/mathjax/2.7.5/MathJax.js?configTeX-AMS-MML_HTMLorMML在文章的上方添加mathjax: true 公式编辑器&#xff1a;点击编辑 行内添加&#xff1a;∂2∂x2\frac{\partial^2 }{\pa…

Revit LT 2022基本培训 Revit LT 2022 Essential Training

Autodesk Revit是当今最流行的建筑信息建模(BIM)解决方案之一。并且&#xff0c;Revit LT提供了该产品的入门级版本&#xff0c;带有成对的向下功能集&#xff0c;非常适合许多BIM工作流。在本课程中&#xff0c;请加入Chant Bright&#xff0c;她首先解释了Revit和Revit LT之间…

华为云电脑.模式_华为云电脑支持全线,Huawei Share免费更新

样张答案&#xff1a;上面黑鲨下面红魔。最近&#xff0c;华为推出了华为云电脑APP。即一款登陆就可以利用云主机的Windows系统在手机和平板上运行PC程序的软件。不过&#xff0c;并不支持所有产品使用。昨天&#xff0c;华为宣布5月14日起&#xff0c;安卓8.0及以上版本的华为…

Web开发七步骤

1. 环境搭建 2. 编码 3. 上线 4. 数据分析 5. 持续交付 6. 遗留系统 7. 回顾与新架构转载于:https://www.cnblogs.com/h-pursuit/p/5261844.html

Sybase IQ导出文件的几种方式

IQ有四种方法&#xff0c;将表的数据导出为文本文件&#xff1a;1、重定向 SELECT * FROM TABLE1 ># D:MYDATATABLE1.TXT -- 文件生成在执行语句的客户端上 2、通过选项导出 SET TEMPORARY OPTION Temp_Extract_Name1 /data/mydata/table1.txt; SET TEMPORARY OPTION Tem…

Window环境下,Qt中文出现乱码解决办法

在头文件声明的地方添加&#xff1a; #pragma execution_character_set("utf-8")#ifndef NETWIDGET_H #define NETWIDGET_H#include <QWidget> #include <QHostInfo> #include <QNetworkInterface> //防止中文出现乱码 #pragma execution_charact…

Revit初学者完整指南 The Complete Revit Guide for Beginners

学习设计、建模、注释和渲染Revit项目 你会学到什么 在Revit中建模 开发建筑信息模型 从模型文件导出图形和图形。 在Revit中渲染 开发参数化建筑和墙截面 开发建筑立面图和平面图 流派:电子学习| MP4 |视频:h264&#xff0c;1280720 |音频:AAC&#xff0c;44.1 KHz 语言&…

HDU5583 上海赛铜牌题

这道题的意思是给你一个01串&#xff0c; 定义这串的优美值为连续相同的数字的平方和&#xff0c; 现在可以改变这些串中一个字符&#xff0c; 问你优美值最大是多少&#xff1f; 我们可以预处理出d1[i]i左边和str[i]相同的字符个数&#xff0c; d2[i]i右边和str[i]相同的字符个…

jquery click 第一次没用_【通知】同济大学研究生会20202021学年第一次主席联席会...

为加强同济大学研究生会与各学院(系)研究生会的交流与合作&#xff0c;促进学校研究生工作的顺利开展&#xff0c;特邀请各院(系、所)研会主席参加本学年第一次主席联席会。同济大学研究生会 2020-2021 学年第一次主席联席会(四平路校区)会议时间2020年10月18日(周日)上午9&…

ref和out 传递参数(C#)

1.参数传递默认都是传递栈空间里面存储的内容 2.如果添加了ref那么传递的都是栈空间地址&#xff0c;而不再是栈空间里面的内容 3.如果添加了out,那么传递的也是栈空间的地址 1 //写一个方法计算一个int类型数组中每个元素的总和以及最大值和最小值2 /// <summary&…