The Clean Architecture(清洁的架构风格)

来源:互联网 发布:mac opengl 编辑:程序博客网 时间:2024/04/30 10:33

这里写图片描述

https://github.com/googlesamples/android-architecture

  • entities:enterprise Business Rules
  • Use Case: Application Business Rules
  • Controllers Presenters Gateways:Interface Adapters
  • Devices Web UI DB External Interfaces:Frameworks & Drivers
  • 实体:企业业务规则
  • 用例:应用业务规则
  • 控制器、呈现者、出入口:接口适配器
  • 设备 Web UI数据库外部接口:框架和驱动程序

Over the last several years we’ve seen a whole range of ideas regarding the architecture of systems. These include:
在过去几年中,我们已经看到了关于系统架构的一系列想法。 这些包括:

  • Hexagonal Architecture (a.k.a. Ports and Adapters) by Alistair Cockburn and adopted by Steve Freeman, and Nat Pryce in their wonderful book Growing Object Oriented Software
  • Onion Architecture by Jeffrey Palermo
  • Screaming Architecture from a blog of mine last year
  • DCI from James Coplien, and Trygve Reenskaug.
  • BCE by Ivar Jacobson from his book Object Oriented Software Engineering: A Use-Case Driven Approach
  • 由Alistair Cockburn编写的六边形体系结构 (又称端口和适配器),由Steve Freeman和Nat Pryce在其优秀的书“Growing Object Oriented Software”
  • 洋葱架构杰弗里巴勒莫
  • 来自去年一个博客的尖叫架构
  • DCI(精益架构(书名):敏捷软件开发) from James Coplien(人名), and Trygve Reenskaug(人名).
  • 由Ivar Jacobson撰写的BCE:“面向对象的软件工程:用例驱动方法”

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.

  1. 独立于框架。 这个架构并不依赖于一些功能强大的软件库的存在。 这允许你使用这样的框架作为工具,而不是把你的系统塞进有限的约束。
  2. 可测试。 业务规则可以在没有UI,数据库,Web服务器或任何其他外部元素的情况下进行测试。
  3. 独立的用户界面。 用户界面可以很容易地更改,而无需更改系统的其他部分。 例如,Web UI可以替换为控制台UI,而无需更改业务规则。
  4. 独立于数据库。 您可以换出Oracle或SQL Server,Mongo,BigTable,CouchDB或其他。 您的业务规则不绑定到数据库。
  5. 独立于任何外部机构。 事实上,你的业务规则根本就不了解外面的世界。

本文顶部的图表是尝试将所有的这些架构体系集成到一个可操作的想法中。

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 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.
我们不希望这一层的变化影响实体。 我们也不希望这个层受到数据库,UI或任何通用框架等外部性的影响。 这一层与这种担忧是分开的。

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.
这一层的软件是一套适配器,可以将数据从用例和实体最方便的格式转换成最适合某些外部机构(如数据库或Web)的格式。例如,这个层将完全包含GUI的MVC体系结构。演示者,视图和控制器都属于这里。模型可能只是从控制器传递给用例的数据结构,然后从用例返回到演示者和视图。

类似地,在这一层,数据从最适合实体和用例的格式转换成最适合于任何持久性框架的形式。即数据库。这个圈子里面的任何代码都不应该对数据库有所了解。如果数据库是一个SQL数据库,那么所有的SQL都应该被限制到这个层,特别是这个层的那些与数据库有关的部分。

在这个层中,还有其他任何必须将数据从外部服务等外部表单转换为用例和实体所使用的内部表单的适配器。

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.

框架和驱动程序。

最外层通常由框架和工具组成,比如数据库,Web框架等。一般来说,除了向下一个圆圈通信的粘合代码以外,在这个层中不会写入太多的代码。

这一层是所有细节去的地方。 网络是一个细节。 数据库是一个细节。 我们把这些东西放在外面,不会有什么伤害。

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.

在图的右下方是我们如何跨越界限的例子。它显示了控制器和演示者与下一层中的用例进行通信。注意控制的流程。它从控制器开始,在用例中移动,然后在演示者中结束执行。还要注意源代码的依赖关系。他们每个人都向内指向用例。

我们通常通过使用依赖倒置原则来解决这个明显的矛盾。例如,在像Java这样的语言中,我们将安排接口和继承关系,以便源代码依赖性在跨越边界的恰当点处反对控制流。

例如,考虑用例需要调用演示者。但是,这个调用不能是直接的,因为这会违反依赖规则:内圈没有提到外圈的名字。所以我们有一个用例调用一个接口(在这里显示为Use Case Output Port),并且让外部的演示者实现它。

同样的技术被用来跨越架构中的所有边界。我们利用动态多态来创建反对控制流的源代码依赖关系,这样无论控制流进入什么方向,我们都可以遵循依赖规则。

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.

什么数据跨越边界。

通常跨越边界的数据是简单的数据结构。 如果你喜欢,你可以使用基本的结构或简单的数据传输对象。 或者数据可以简单地作为函数调用的参数。 或者你可以把它打包成一个hashmap,或者把它构造成一个对象。 重要的是,隔离的,简单的数据结构是跨越边界传递的。 我们不想欺骗和传递实体或数据库行。 我们不希望数据结构有任何违反依赖规则的依赖。

例如,许多数据库框架响应查询返回一个方便的数据格式。 我们可以称之为RowStructure。 我们不希望跨越边界向内传递该行结构。 这将违反依赖规则,因为这会迫使内圈知道一些关于外圈的内容。

所以当我们通过边界传递数据的时候,总是以内圈最方便的形式出现。

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.

结论

遵守这些简单的规则并不难,而且会为您节省很多麻烦。 通过将软件分成不同的层次,并符合依赖规则,您将创建一个本质上可测试的系统,并具有所有的好处。 当系统的任何外部部件变得过时时,如数据库或Web框架,可以用最少的工作量替换那些过时的元素。

原创粉丝点击