1 高内聚、低耦合

虽然已经毕业很多年了,但依然总是能记得,《软件工程》这门课的老师总是强调 "高内聚,低耦合"。

这些年,在架构方面的技术发展方向,目标就是不断的拆分代码。

其本质就是 —— 提高内聚性、降低耦合度。

2 我们要拆分什么?

为了降低程序的耦合度,我们总是把代码拆分的更细小。

  • 我们拆分业务,得到微服务。
  • 我们拆分出 表现 - 控制 - 模型,得到了 MVC。
  • 我们拆分出 交互 - 逻辑 - 存储,得到了三层模式。

每一次的拆分,都是对单个职责的细化。

现如今,我们的代码基本上是这样子的:(下面的例子是由用户角度出度,以数据方向顺序来举例的 )

  1. 前台是由 webpack 打包的单页面应用
  2. 利用 ajax 将请求发送到 WebApi 上
  3. WebApi 根据 http 请求调度相应的 Controller
  4. 我们在 Controller 层调用相应的 Service
  5. Service 调用相应的 RepositoryDao 或是其它什么数据持久层

我们根据不同的关注点,拆分成了不同的层次:前台、Controller 层、Service 层、等等。。。。

2.1 前台

我们其实可以把前台看作一个独立的应用,它其实同样需要拆分,这里我就不细谈了。

2.2 Controller

无论是哪种的 Web 服务器、无论哪种开发语言,都会将接收的 Http 请求,转换成为某种固定的数据结构。

笼统的说,接下来程序要做的事情,就是拿着这个数据结构,根据里面数据的不同,去找一个 Controller 去执行。

这个 Controller 就是这个 Http 请求的接受者

流程大致如下:

  1. 将 Http 请求封闭成一个 固定的数据结构
  2. 根据预设的规则,分析这个 固定的数据结构 ,创建一个 Controller

可以看出来,无论是哪种情况,它们在调用 Controller 前,都是同一个数据结构。

2.3 Service 

大家也许并没有留意这个细节,

Service 的调用是一种同时要求知道 数据结构 和 接受者 的过程。

 public class SomeController
{
private readonly ISomeService someService; public SomeController(ISomeService someService)
{
this.someService = someService;
} [HttpPost("Create")]
public SomeDto CreateSomething(SomethingDto parameters)
{
return this.someService.Create(new Something()
{
A = paraeters.A
// and so on
});
}
}

从上面的代码可以看出来,当我们意图创建一个 Something 的时候,我们需要知道三件事

  1. 我们需要使用哪个 Service
  2. 我们需要调用 Service 上的哪个方法
  3. 我们需要以何种数据结构调用 Service 的方法

再对比 Http - Controller 之间的关系,就会发现不同了。

  Controller 调用 Service 调用
数据结构 始终相同 不同的 Service,基本都不一样
数据接受方 不需要知道 需要知道
接受方的方法 不需要知道 需要知道

很明显,Controller 调用方法更好,它的调用方法几乎不需要依赖太多的信息。

我们把这种调用的方式,称为 命令总线。

2 命令总线

命令总线 就像一个黑盒子,你要做的就是把命令放进去,然后结果就弹出来了。

至于一个命令如何去找到它的处理者,那肯定是有一定 规则。

有了 命令总线,有些事情就发生了变化。

不再需要问这个功能在哪个 Service 上了,只要知道这个功能用哪个命令就行了。

实际研发过程中,总有一些功能,放哪个 Service 上都可以,也都不完全合适。

但是把它看过一个命令,就不再会有任何的不合适了。

3 Reface.CommandBus

Reface.CommandBus 这是一个基于 .NetFramework 4.6.1 开发的 命令总线 工具库。

你可以用这个工具库创建命令,并且透明化的执行这些命令并得到结果。

3.1 相关地址

3.2 使用方法

3.2.1 创建命令

所有的命令都必须实现 ICommand 这个无内容的接口。

广义上的命令,是一个开放的,无约束的数据结构。

但是在某些特殊的使用场景下,我们可以使用统一的数据结构作为命令的载体,更可以使用统一的数据结构作为响应的载体。

    public class ACommand : ICommand
{
// 这里可以编写你需要的参数
}

3.2.2 创建命令处理器

命令处理器需要实现 ICommandHandler<T> 接口,其中泛型 T 就是待处理的 Command 的类型。

    public class ACommandHandler : ICommandHandler<ACommand>
{
public object Handler(ACommand command)
{
return "A";
}
}

3.3.3 将处理器注册到总线中

将处理器注册到总线中,是通过向 处理器工厂 实现的,当前版本中,有两个 处理器工厂 类型

  • DefaultCommandHandlerFactory,这是一个基于硬编码注册的工厂
  • ConfigurationCommandHandlerFactory,这是一个基于读取 .config 文件进行注册的工厂,Github 上有关于配置的方法,比较简单。

你也可以定制自己的 处理器工厂 完成更好的从注册到创建过程。

这里还有一个扩展库 [ Reface.CommandBus.IntegrateAutofac ] ,是于 Autofac 集成后,以程序集为单位进行 处理器 注册的实现,可以通过 nuget 安装得到。

3.3.4 创建 ICommandBus 实例

目前库内自带的是 DefaultCommandBus 实例

ICommandBus bus = new DefaultCommandBus(factory); // facotry 就是 ICommandHandlerFactory 的实例
ACommand cmd = new ACommand();
string result = bus.Dispatch<ACommand, string>(cmd);

result 就是执行结果。


通过这种模式对命令的调用,可以让命令发起方只需要关心使用哪个命令和返回的结果类型就可以了。

在比较小的应用领域,可以统一命令结构和响应结构。

[C#] 命令总线模式的更多相关文章

  1. 好压(HaoZip)的命令行模式用法介绍

    好压压缩软件,又叫“2345好压”,是一款国产的优秀压缩软件,目前是免费的,据官网介绍,该软件永久免费.官网地址:http://haozip.2345.com/ 本文主要对该软件的命令行模式用法进行介 ...

  2. WinRAR的命令行模式用法介绍

    因工作中要对数据打包,顺便研究了下WinRAR的命令行模式,自己写了些例子,基本用法如下: 测试压缩文件准备:文件夹test_data,内部包含子文件夹,分别存放了一些*.log和*.txt文件. 测 ...

  3. 命令行模式 svn版本管理

    linux 下svn 在命令行模式下的操作安装完svn服务并配置了环境变量之后,要创建一个存放工厂(项目)的仓库repositories用于版本控制(比如我的repositories的路径为 path ...

  4. Linux 命令行模式 你需要知道的那些事

    注: 安装软件 pip install + 软件名  例如: pip install xadmin 卸载软件 pip uninstall + 软件名 例如 pip uninstall xadmin 安 ...

  5. 如何在命令行模式下查看Python帮助文档---dir、help、__doc__

    如何在命令行模式下查看Python帮助文档---dir.help.__doc__ 1.dir函数式可以查看对象的属性,使用方法很简单,举str类型为例,在Python命令窗口输入 dir(str) 即 ...

  6. Linux 开机启动方式设置 inittab 详解,开机直接进入“命令行”模式

    Linux下的 /etc/inittab 中的英文解释: This file describes how the INIT process should set up  the system in a ...

  7. Ubuntu 开机进入命令行模式

    1.修改配置 sudo vim /etc/default/grub 把 GRUB_CMDLINE_LINUX_DEFAULT="quiet splash" 改为 GRUB_CMDL ...

  8. 命令行模式下 MYSQL导入导出.sql文件的方法

    一.MYSQL的命令行模式的设置:桌面->我的电脑->属性->环境变量->新建->PATH=“:path\mysql\bin;”其中path为MYSQL的安装路径.二.简 ...

  9. [转载] ubuntu开机直接进入命令行模式

    最近安装了ubuntu12.04来使用,每次都进入unity界面再进入命令行很不方便. 不需要界面的话,可以通过设置来开机进入命令行模式. 今天提供两中比较好的方法.经本人测试两中方法都可使用. [1 ...

随机推荐

  1. 吴裕雄--天生自然python学习笔记:Python CGI编程

    什么是CGI CGI 目前由NCSA维护,NCSA定义CGI如下: CGI(Common Gateway Interface),通用网关接口,它是一段程序,运行在服务器上如:HTTP服务器,提供同客户 ...

  2. java操作telnet远程登录

    import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import jav ...

  3. Docker私有仓库管理

    docker load -i registry.tar.gz docker run -d -p 5000:5000 --restart=always --name registry -v /opt/m ...

  4. Trie图 模板

    trie图实际上是优化的一种AC自动机. trie图是在trie树上加一些失配指针,实际上是类似KMP的一种字符串匹配算法. 失配指针类似KMP的nx数组,有效地利用了之前失配的信息,优化了时间复杂度 ...

  5. Servlet与JSP概念理解

    Servlet是用Java编写的服务端程序.需要部署到servlet容器上才能运行,tomcat 就是一个servlet容器. 1.Servlet的生命周期 客户端请求该 Servlet --> ...

  6. Proto3:C++代码生成指南

    本章节实际上是介绍Protocol Buffer编译器从给定的protocol定义中生成的C++代码.所有proto2和proto3生成的代码不同之处都会高亮标出 --- 需要注意的是这些不同之处只是 ...

  7. 如何安装及使用honmaple社区程序 · honmaple's blog · 风落花语风落天,花落风雨花落田.

    Table of Contents 1. 如何安装及使用 1.1. 安装需要的package 1.2. 配置config 1.3. 注释下面代码 1.4. 初始化数据库 1.5. 创建管理员账户 2. ...

  8. HTTP协议 有这篇文章足够了

    HTTP 协议详解 HTTP(HyperText Transfer Protocol)超文本传输协议.其最初的设计目的是为了提供一种发布和接收HTML页面的方法. HTTP是一个客户端(用户)和服务端 ...

  9. Windows GDI 窗口与 Direct3D 屏幕截图

    前言 Windows 上,屏幕截图一般是调用 win32 api 完成的,如果 C# 想实现截图功能,就需要封装相关 api.在 Windows 上,主要图形接口有 GDI 和 DirectX.GDI ...

  10. nginx能访问html静态文件但无法访问php文件

    nginx.conf中红框部分修改成你的实际网站根目录