地址:http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html

Over the last several years we’ve seen a whole range of ideas regarding the architecture of systems. These include:

Though these architectures all vary somewhat in their details, they are very similar. They all have the same objective, which is the separation of concerns. They all achieve this separation by dividing the software into layers. Each has at least one layer for business rules, and another for interfaces.

Each of these architectures produce systems that are:

  1. Independent of Frameworks. The architecture does not depend on the existence of some library of feature laden software. This allows you to use such frameworks as tools, rather than having to cram your system into their limited constraints.
  2. Testable. The business rules can be tested without the UI, Database, Web Server, or any other external element.
  3. Independent of UI. The UI can change easily, without changing the rest of the system. A Web UI could be replaced with a console UI, for example, without changing the business rules.
  4. Independent of Database. You can swap out Oracle or SQL Server, for Mongo, BigTable, CouchDB, or something else. Your business rules are not bound to the database.
  5. Independent of any external agency. In fact your business rules simply don’t know anything at all about the outside world.

The diagram at the top of this article is an attempt at integrating all these architectures into a single actionable idea.

The Dependency Rule

The concentric circles represent different areas of software. In general, the further in you go, the higher level the software becomes. The outer circles are mechanisms. The inner circles are policies.

The overriding rule that makes this architecture work is The Dependency Rule. This rule says that source code dependencies can only point inwards. Nothing in an inner circle can know anything at all about something in an outer circle. In particular, the name of something declared in an outer circle must not be mentioned by the code in the an inner circle. That includes, functions, classes. variables, or any other named software entity.

By the same token, data formats used in an outer circle should not be used by an inner circle, especially if those formats are generate by a framework in an outer circle. We don’t want anything in an outer circle to impact the inner circles.

Entities

Entities encapsulate Enterprise wide business rules. An entity can be an object with methods, or it can be a set of data structures and functions. It doesn’t matter so long as the entities could be used by many different applications in the enterprise.

If you don’t have an enterprise, and are just writing a single application, then these entities are the business objects of the application. They encapsulate the most general and high-level rules. They are the least likely to change when something external changes. For example, you would not expect these objects to be affected by a change to page navigation, or security. No operational change to any particular application should affect the entity layer.

Use Cases

The software in this layer contains application specific business rules. It encapsulates and implements all of the use cases of the system. These use cases orchestrate the flow of data to and from the entities, and direct those entities to use their enterprise wide business rules to achieve the goals of the use case.

We do not expect changes in this layer to affect the entities. We also do not expect this layer to be affected by changes to externalities such as the database, the UI, or any of the common frameworks. This layer is isolated from such concerns.

We do, however, expect that changes to the operation of the application will affect the use-cases and therefore the software in this layer. If the details of a use-case change, then some code in this layer will certainly be affected.

Interface Adapters

The software in this layer is a set of adapters that convert data from the format most convenient for the use cases and entities, to the format most convenient for some external agency such as the Database or the Web. It is this layer, for example, that will wholly contain the MVC architecture of a GUI. The Presenters, Views, and Controllers all belong in here. The models are likely just data structures that are passed from the controllers to the use cases, and then back from the use cases to the presenters and views.

Similarly, data is converted, in this layer, from the form most convenient for entities and use cases, into the form most convenient for whatever persistence framework is being used. i.e. The Database. No code inward of this circle should know anything at all about the database. If the database is a SQL database, then all the SQL should be restricted to this layer, and in particular to the parts of this layer that have to do with the database.

Also in this layer is any other adapter necessary to convert data from some external form, such as an external service, to the internal form used by the use cases and entities.

Frameworks and Drivers.

The outermost layer is generally composed of frameworks and tools such as the Database, the Web Framework, etc. Generally you don’t write much code in this layer other than glue code that communicates to the next circle inwards.

This layer is where all the details go. The Web is a detail. The database is a detail. We keep these things on the outside where they can do little harm.

Only Four Circles?

No, the circles are schematic. You may find that you need more than just these four. There’s no rule that says you must always have just these four. However, The Dependency Rule always applies. Source code dependencies always point inwards. As you move inwards the level of abstraction increases. The outermost circle is low level concrete detail. As you move inwards the software grows more abstract, and encapsulates higher level policies. The inner most circle is the most general.

Crossing boundaries.

At the lower right of the diagram is an example of how we cross the circle boundaries. It shows the Controllers and Presenters communicating with the Use Cases in the next layer. Note the flow of control. It begins in the controller, moves through the use case, and then winds up executing in the presenter. Note also the source code dependencies. Each one of them points inwards towards the use cases.

We usually resolve this apparent contradiction by using the Dependency Inversion Principle. In a language like Java, for example, we would arrange interfaces and inheritance relationships such that the source code dependencies oppose the flow of control at just the right points across the boundary.

For example, consider that the use case needs to call the presenter. However, this call must not be direct because that would violate The Dependency Rule: No name in an outer circle can be mentioned by an inner circle. So we have the use case call an interface (Shown here as Use Case Output Port) in the inner circle, and have the presenter in the outer circle implement it.

The same technique is used to cross all the boundaries in the architectures. We take advantage of dynamic polymorphism to create source code dependencies that oppose the flow of control so that we can conform to The Dependency Rule no matter what direction the flow of control is going in.

What data crosses the boundaries.

Typically the data that crosses the boundaries is simple data structures. You can use basic structs or simple Data Transfer objects if you like. Or the data can simply be arguments in function calls. Or you can pack it into a hashmap, or construct it into an object. The important thing is that isolated, simple, data structures are passed across the boundaries. We don’t want to cheat and pass Entities or Database rows. We don’t want the data structures to have any kind of dependency that violates The Dependency Rule.

For example, many database frameworks return a convenient data format in response to a query. We might call this a RowStructure. We don’t want to pass that row structure inwards across a boundary. That would violate The Dependency Rule because it would force an inner circle to know something about an outer circle.

So when we pass data across a boundary, it is always in the form that is most convenient for the inner circle.

Conclusion

Conforming to these simple rules is not hard, and will save you a lot of headaches going forward. By separating the software into layers, and conforming to The Dependency Rule, you will create a system that is intrinsically testable, with all the benefits that implies. When any of the external parts of the system become obsolete, like the database, or the web framework, you can replace those obsolete elements with a minimum of fuss.

Robert Martin (Uncle Bob) is 8th Light's Master Craftsman. He's an award winning author, renowned speaker, and über software geek since 1970.

TweetFollow @unclebobmartin

架构:The Clean Architecture(整洁的架构)(转载)的更多相关文章

  1. 干净的架构The Clean Architecture

    干净的架构The Clean Architecture 这是著名软件大师Bob大叔提出的一种架构,也是当前各种语言开发架构.干净架构提出了一种单向依赖关系,从而从逻辑上形成一种向上的抽象系统. 我们经 ...

  2. 清晰架构(Clean Architecture)的Go微服务: 程序结构

    我使用Go和gRPC创建了一个微服务,并试图找出最佳的程序结构,它可以用作我未来程序的模板. 我有Java背景,并发现自己在Java和Go之间挣扎,它们之间的编程理念完全不同.我写了一系列关于在项目工 ...

  3. 清晰架构(Clean Architecture)的Go微服务: 设计原则

    我最近写了一个Go微服务应用程序,这个程序的设计来自三个灵感: 清晰架构"Clean Architecture"¹ and SOLID (面向对象设计)² 设计 原则³ Sprin ...

  4. 清晰架构(Clean Architecture)的Go微服务: 程序容器(Application Container)

    清晰架构(Clean Architecture)的一个理念是隔离程序的框架,使框架不会接管你的应用程序,而是由你决定何时何地使用它们.在本程序中,我特意不在开始时使用任何框架,因此我可以更好地控制程序 ...

  5. 清晰架构(Clean Architecture)的Go微服务: 依赖注入(Dependency Injection)

    在清晰架构(Clean Architecture)中,应用程序的每一层(用例,数据服务和域模型)仅依赖于其他层的接口而不是具体类型. 在运行时,程序容器¹负责创建具体类型并将它们注入到每个函数中,它使 ...

  6. 清晰架构(Clean Architecture)的Go微服务: 编码风格

    编码风格在编程中是一个相对乏味的主题,但是合适的编码风格对一个有效的程序员是至关重要的. 它有三个组成部分: 程序结构 ( application layout) 编码规则或风格 命名约定 我已经在清 ...

  7. 清晰架构(Clean Architecture)的Go微服务

    我用Go和gRPC创建了一个微服务项目,并试图找出最好的程序结构,它可以作为我其他项目的模板.我还将程序设计和编程的最佳实践应用于Go Microservice程序,例如清晰架构(Clean Arch ...

  8. 清晰架构(Clean Architecture)的Go微服务: 程序设计

    我使用Go和gRPC创建了一个微服务,并将程序设计和编程的最佳实践应用于该项目. 我写了一系列关于在项目工作中做出的设计决策和取舍的文章,此篇是关于程序设计. 程序的设计遵循清晰架构(Clean Ar ...

  9. 清晰架构(Clean Architecture)的Go微服务—重大升级

    去年,我创建了一个清晰架构(Clean Architecture)微服务框架,它功能强大,但有些重.我写了一个系列文章来讲述它,请参阅"清晰架构(Clean Architecture)的Go ...

  10. 清晰架构(Clean Architecture)的Go微服务: 事物管理

    为了支持业务层中的事务,我试图在Go中查找类似Spring的声明式事务管理,但是没找到,所以我决定自己写一个. 事务很容易在Go中实现,但很难做到正确地实现. 需求: 将业务逻辑与事务代码分开. 在编 ...

随机推荐

  1. 利用CSS改变输入框的光标颜色

    转:http://www.cnblogs.com/gymmer/p/6810367.html 代码: <!DOCTYPE html> <html lang="en" ...

  2. hadoop-2.7.2-HA安装笔记

    配置方案如图   NN DN ZK ZKFC JN RM NM(任务管理器) HMaster Region Server Node1 1 1 1 1 1 Node2 1 1 1 1 1 1 1 Nod ...

  3. selenium 操作文本框(textarea输入)

    selenium 对文本框的输入操作一般有两种形式,传统的是直接通过定位元素通过sendKeys()方法直接在文本框中输入信息.但有时候我们可以通过id 的方式将其进行定位,但却不能通过sendKey ...

  4. [转]Javascript原型继承

    真正意义上来说Javascript并不是一门面向对象的语言,没有提供传统的继承方式,但是它提供了一种原型继承的方式,利用自身提供的原型属性来实现继承.Javascript原型继承是一个被说烂掉了的话题 ...

  5. 【深入Struts2】获取ServletAPI的三种方式

    一:获取servletAPI的三种方法 在传统的Web开发中,经常会用到Servlet API中的HttpServletRequest.HttpSession和ServletContext.Strut ...

  6. Codeforces 379F New Year Tree 树的直径的性质推理

    New Year Tree 我们假设当前的直径两端为A, B, 那么现在加入v的两个儿子x, y. 求直径的话我们可以第一次dfs找到最远点这个点必定为直径上的点, 然而用这个点第二次dfs找到最远点 ...

  7. C#简单的通用分页

    通用分页技术分析 需要返回不同的类型的数据--采用泛型实现该操作 需要提供不同的方法 上一页 上一页 第一页 最后一页 跳转到指定页 Demo 代码 using System; using Syste ...

  8. swiper实例应用

    1.手机竖屏单页滑 为了防止图压缩,单独切图,背景用纯色 2.自由滑 很长的图,自由切割

  9. 不同浏览器的userAgent

    一.IE浏览器 //IE6 "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" //IE7 "Mozill ...

  10. Bzoj4558:分类讨论 计算几何 组合数学

    国际惯例的题面: 这题让我爆肝啦......这种计数显然容斥,正好不含任何坏点的我们不会算,但是我们能算至少含零个坏点的,至少含一个坏点的,至少含两个坏点的......所以最终的答案就是(至少含零个坏 ...