ylm's space

null

导航

分层模式

    分层模式是我们在软件设计时用的最多的技术之一。分层模式中最困难的是决定哪些层以及每一层的职责是什么,如何分层。分多少层是根据业务逻辑的复杂性,尽管它目前还无法量化,甚至无法根据某种精度加以限制。还有一些其他的选择依据,例如与数据库连接的难易程度等。在这里我们介绍一些众所周知的分层策略。

    Layers模式(两层应用程序)

    当我们使用一个大型复杂系统时希望将通过分解来管理复杂事务,但是如何组织应用程序,以便满足可维护性,可扩展性、可伸缩性、稳定性以及安全性等要求?该解决方案由一组层组成。每层都应保持内聚性,并且应大致位于同一抽象级别。每一层都应与下面的各层保持松散耦合。这就是一个简单的Layers模式解决的过程,用在相对简单的客户端应用程序(标准情况是两层应用程序)。

    这个简单的应用程序组织策略有助于解决软件开发中面临的两个挑战:依存关系的管理和对可交换组件的需求。如果在构件应用程序时没有一个考虑周全的依存关系管理策略,会导致组件易损坏而且不牢靠,从而导致对他们的进行维护、扩展和替代存在交大的困难,而且成本较高。

    Layers 模式的通用性足以应用于诸如网络协议、平台软件和虚拟机之类的领域,但是它无法解决企业类业务解决方案中存在的某些特定问题。例如,除通过分解来管理复杂性(由 Layers 解决的基本问题)外,业务解决方案开发人员还需要进行适当组织,以便有效地重复使用业务逻辑并保留与昂贵资源(如数据库)的重要连接。解决此问题的方法之一就是使用 三层应用程序模式。

三层应用程序模式(Three-Layered Application)

   三层应用程序模式是我们最常用的模式之一。当我们在准备使用层来组织应用程序的方式构件一个业务解决方法,如何组织应用程序以便重用业务逻辑、提供部署灵活性并保留重要的资源连接?这就可以用三层应用程序模式。

  常见的三层应用程序模式常见的有microsoft DNAMartin Fowler的。

microsoft DNA架构定义了三个层次:表现层、业务层和数据访问层。

          microsoft DNA                       Fowler

             表现层                                   表现层

                业务层                                   领域层

               数据访问层                           数据源层

 三层:表示层、业务逻辑层和数据访问层。

   表现层:这一层负责与用户的交互。提供服务,显示信息(例如在windowsHTML页面中,处理用户请求(鼠标点击,键盘敲击等),HTTP请求,命令行调用。处理API

   业务层/ 领域层:逻辑,系统中真正的核心。业务层实现应用程序的业务功能。

   数据访问层/数据源层:与数据库、消息系统、事务管理器及其其他软件包通信。  

  microsoft DNAFowler两个主要的区别在于数据从数据访问层向上层传递的方式。microsoft DNA所有层都操作在数据访问层通过查询访问数据库产生的记录集上。这就带来一个耦合的问题--无论是业务层还是表现层,都必须了解数据库。数据集就相当于数据传输对象。但是随着对.net的深入研究传统模式在.net中的应用,根据需要在选择合适的数据传输对象。

.NET PetShop 按照三层的分层模型来部署整个系统。这三层被清晰的分割为分布式应用的三个方面。其中表现层主要是完成界面和与最终用户交互的功能,在应用程序里面是一些 Asp.NET 的页面和代码;中间层用于封装商业逻辑和规则,在应用程序里面被封装为 .NET 组件;数据访问通过中间层中的数据访问组件与 SQL Server 交互,所有的数据获取依靠存储过程来进行,而不是通过 SQL 语句。但是在PetShop它是通过DataReader传输数据的。其实DataReader不能算做数据传输对象,但是它适合PetShop应用程序。

其实Layers和三层应用程序模式就是在Layers基础上进行简单的优化,在Layers中确定的环境、影响因素解决方案仍适用于三层应用程序模式,但反之不行。也就是说Layers模式约束着三层应用程序模式,而三层应用程序模式优化了Layers模式。这种模式关系对复杂性管理非常有用。当你理解某中模式之后,肯定只是了解初始模式与优化模式之间的递增区别。另一个事例(这次涉及Web Service 领域)应该有助于阐明优化的概念。

当我们设计复杂的企业应用程序时,我们可能会向特定的层中添加组件,这样有时会是Layered Application(分层应用程序)的优势逐渐消失,也有可能成为一团糟。这是我们就会将一些服务接口转移到一个单独的层中。也可以将业务层分成域层和应用程序层。这样我们常用的三层会扩展到四层、五层、六层或者甚至。

Duwamish 7.0 架构共分成四层:Web 层,业务外观层,业务逻辑层,数据访问层。

  Web 层:为客户端提供对应用程序的访问。这一层是作为 Duwamish.sln 解决方案文件中的 Web 项目实现的。Web 层由 ASP.NET Web 窗体和代码隐藏文件组成。Web 窗体只是用 HTML 提供用户操作,而代码隐藏文件实现各种控件的事件处理。

业务外观层:为 Web 层提供处理帐户、类别浏览和购书的界面。这一层是作为 Duwamish.sln 解决方案文件中的 BusinessFacade 项目实现的。业务外观层用作隔离层,它将用户界面与各种业务功能的实现隔离开来。除了低级系统和支持功能之外,对数据库服务器的所有调用都是通过此程序集进行的。

业务逻辑层:各种业务规则和逻辑的实现。业务规则层是作为 Duwamish.sln 解决方案文件中的 BusinessRules 项目实现的。

数据访问层:数据访问层为业务规则层提供数据服务。这一层是作为 Duwamish.sln 解决方案文件中的 DataAccess 项目实现的。

其实它就是把三层中的表示层分为Web 层和业务外观层。

我们在扩展层的时候必须协调下列的影响因素:

     每一层中的组件应保持内聚性,并且应大致在同一抽象级别。每一层都应与它下面的各层保持松散耦合。

   仅限于对解决方案的某一部分进行更改以便尽量降低对其他部分的影响,从而减少调试和纠错的工作量,使应用程序易于维护,并增强应用程序的总体灵活性。

将所关注的问题分隔在不同的组件中(例如,将用户界面和业务逻辑分隔开来,并将业务逻辑与数据库分隔开来),以增强灵活性、可维护性和可伸缩性。

  组件应该可被多个应用程序重用。

 独立团队应该能够在处理解决方案的各个部分时尽量减少对其他团队的依赖,并且能够针对定义明确的接口展开开发工作。

各个组件应保持内聚性。

无关的组件应保持松散耦合。

应按照不同的时间安排,独立部署、维护和更新解决方案的各个组件。

 跨越过多的组件边界会对性能造成不利的影响。

 要使web应用程序既安全又可访问,需要将应用程序分布在多个物理级。这使的你可以保护应用程序位于防火墙后面的,并是其他组件可从Internet 被访问到。

   要确保高性能和高可靠性,解决方案必须是可测试的。

Layered Application(分层应用程序)

其实以上它们都是Layered Application(分层应用程序). 分层应用程序中每一层中的组件应保持内聚性,并且应大致在同一抽象级别。每一层都应与它下面的各层保持松散耦合。Pattern-Oriented Software Architecture, Vol 1 [Buschmann96]对分层过程的描述如下:

    从最低级别的抽象开始--称为第 1 层。这是系统的基础。通过将第 J 层放置在第 J-1 层的上面逐步向上完成抽象阶梯,直到到达功能的最高级别 - 称为第 N 层。    

    Layered Application的关键是倚赖管理。一层中的组件只能与同一级别中的对等实体或较低级别中的组件交互。这有助于减少不同级别中的组件之间的依赖性。在使用的时候我们可以根据我们的需要来使用严格分层或松散分层。 严格分层是一层中的组件只能与对等实体以及与它紧邻的下面一层进行交互。松散的分层应用程序放宽了此限制,它允许组件与位于它下面的任意层中的组件进行交互。 松散方法可以改善效率,因为系统不必将简单调用从一层转发到下一层。另一方面,松散方法在层之间不提供隔离级别,并使的在不影响较高层的情况下换出较低层变的更困难。 对于包含许多软件组件的大型解决方案,常见的方法是使不内聚的大量组件处于同一抽象级别。在这种情况下,每一层可以进一步分解为一个或多个内聚的子系统。

   通常使用下列技术扩充基本的 Layered Application 模式。

   Layer Supertype(层超类型). 如果一层中的组件具有相同的一组行为,就可以将这些行为提取到一个公共类或组件中,并使层中的所有组件都继承该公共类或组件。这不仅简化维护并提高了可重用性,还允许通过对超类型(而不是特定的组件)的运行时引用来调用公共行为,从而减少了层之间的依赖性。

   抽象接口(Layer Facade).对于大型系统,常见的方法是使用Facade 模式来为层或子系统提供单个统一接口,而不是为每个公开的组件分别开发一个抽象接口.这使得层之间具有最低的耦合,因为较高级别组件仅直接引用外观.请务必认真设计外观.在后期改变是非常困难的,因为有许多组件都将依赖于它. 

   当我们在实现Layered Application 模式有两种基本的方法:创建自己的分层架构和重用现有的分层架构。

   创建自己的分层架构: 对于每个企业应用,尽管我们能够区分出其中的主要表现层、业务逻辑层和数据层,但是具体如何分离要取决于应用的复杂程度。伴随着分离,还有一条依赖性原则:业务逻辑层和数据源层绝对不要倚赖于表现层。也就是说,在业务逻辑层和数据层的代码中,不要出现调用表现层代码的情况。这条规则将简化在相同的基础上替换表现层的代价,也使的表现层的修改所带来的连锁反映尽可能小。业务逻辑层与数据源层的关系更复杂,其取决于数据源层的架构模式。

    使用业务逻辑时,其中最大的困难就是区分什么是业务逻辑,什么是其他逻辑。一种不太正规的测试办法就是:假想向系统中增加一个完全不同的新层,例如为web应用增加一个命令行界面层。如果在这个过程中,发现需要重复实现某些功能,则说明可能有一些本应该在业务逻辑层实现的逻辑,现在在表现层实现了。例如:如果一个系统有一张产品列表,其中,当月销售比上个月销售量大10%的产品需要用红色显示。为实现这个功能,开发者在表现层逻辑中比较当月和上个月的销售量,然后将差别大于10%的产品显示为红色。

    这样做的麻烦就是将业务逻辑放到了表现层中,为了进行适当分离,需要在业务逻辑层中定义一个方法,用来指示该产品的销售是否较上个月有较大的提高。该方法返回一个布尔值。表现层则只需要简单的调用一下这个方法,如果为真则用红色表现。 

    定义每一级别之间的接口以及它们彼此通信所需的协议.要避免使较底级别依赖于较高级别,应对需要穿越栈的通信使用异步消息传递,回调和事件技术.同样UML序列图是确保你的接口组完整一致的理想工具.该图因为你判断接口和协议的粒度或详细性提供了一种可视化线索.请特别注意给顶方案中跨越边界的次数,并寻找机会以便重新调整设计以减少跨越边界的次数.关键的设计决策是确定级别的实现细节.应研究Facade 等模式以及其他去耦合技术,以便将这种类型的耦合控制在最小. 

   设计层的实现.已有的面向对象的设计很适合欲这一任务.请务必考虑AdapterBridge Strategy等模式,以便可以通过多种方法实现给定层的接口.当要测试接口和级别实现时,这一功能尤为重要.另一关键的设计决策是考虑如何处理错误.必须定义对于所有级别而言一致的错误处理策略.当设计错误处理策略时,应考虑下列因素: 

  尽可能在最低级别处理错误。  

  避免通过异常处理机制将较低级别抽象公开给较高级别。 

  如果您必须使异常沿栈上移,那么应将较低级别异常转化为对于处理层而言有一定意义的异常。

  另一种方法是重用现有的参考分层应用程序,以便为您的应用程序提供所需的结构。规范的三层应用程序由下列三层组成:表示、域和数据源。即便像这么简单的事物也需要经过很多的努力才能实现 Layered Application 模式所具有的优点。

   Layered Application 具有下列优缺点:

   优点:

   由于层之间的低耦合、层之间的高内聚,以及交换层接口的不同实现的能力,解决方案的维护和增强变得更容易。

   其他解决方案应该能够重用各个层所公开的功能,尤其在设计层接口时考虑到了重用的情况下更应如此。

   如果分布式开发可以分布在层边界,那么此项工作将会变得更容易。

   具有定义明确的层接口以及交换层接口的各个实现的能力提高了可测试性。

   缺点:

   穿越各层(而不是直接调用组件)所需的额外开销会对性能造成不利的影响。要帮助弥补性能损失,可以使用松散的分层方法。通过这种方法,较高层可以直接调用较低层。

   如果分层禁止使用与数据库直接交互的用户界面组件,那么开发用户密集的应用程序有时可能需要更长的时间。

   层的使用有助于控制和封装大型应用程序的复杂性,但增加了简单应用程序的复杂性。

   对较低级别接口的改变可能会渗透到较高级别,尤其是在使用了松散的分层方法的情况下可能性更大。    

  Web Service越来越成熟越来越广泛以后,虽然它是应用集成技术而不是构建的技术,但是它还是改进了我们以上所说的三层应用程序模式。 当我们为某个发展迅速的成功企业够建一个查询股票价格系统。现在,希望通过向业务合作伙伴公开自己的查询服务并将其他合作伙伴服务集成到该查询系统来扩展该应用程序。我们将如何构造自己的业务应用程序以提供和享受服务?

  解决次问题的方案之一是通过将其他与服务有关的职责添加到每一层来扩展三层应用程序模式。在业务层添加了以下职责:通过 Service Interfaces(服务接口)向客户应用程序提供一组简化的操作。数据访问层职责拓宽到了数据库和主机集成之外,一包括与其他服务提供着通信。将数据访问层的这个附加功能封装到服务接口组件中,这些组件负责连接到服务(同步或异步)管理服务的基本会话状态并向业务流程组件通知与服务相关的重大事件。这就是我们下面介绍的Three-Layered Services Application(三层服务应用程序)。

  Three-Layered Services Application(三层服务应用程序)

   该方案使用表示层,业务层与数据访问层来组织您的应用程序,然后其他应用程序可以使用这些服务,而且我们应用程序可以使用其他服务。解决的办法就是应用程序逻辑分解为一组协作服务,每种服务提供整体系统功能的一部分。接着在域层为每个服务表识一个服务接口,该服务接口是独立于基础实现的。最后,扩展数据访问层,以便使用服务网关与其他服务提供程序通信,如果应用程序导航逻辑十分复杂,可以将用户接口过程视为表示层的一部分,以便封装和重用次逻辑。

  表示.表示层提供应用程序的用户界面(UI).这通常包括 Windows 窗体(用于智能客户端应用程序)和 ASP.NET 技术(用于基于浏览器的交互)的使用。

 大多数业务应用程序都使用窗体来构造表示层。应用程序由一系列用户与之交互的窗体(页面)组成。每个窗体都包含许多用于显示较低层的输出以及收集用户输入的字段。

业务.业务曾实现应用程序的业务功能.域层通常由一种或多种支持.NET 的编程语言实现的大量组件组成。这些组件可能成为实现可伸缩的分布式解决方案而以Microsoft? .NET Enterprise Services 进行了扩充,或者为实现工作流编排而以 Microsoft BizTalk? Server 进行了扩展。 大型企业应用程序通常是围绕业务流程和业务组件的概念构造的。这些概念是通过业务层中的大量组件、实体、代理和界面来处理的。

  数据。数据层提供对外部系统(如数据库)的访问。该层涉及到的主要 .NET 技术是 ADO.NET。但是,在这里也经常用到一些 .NET XML 功能。

   在构建三层服务应用程序时应该考虑除了Layered Application 中讨论的影响因素外  

   始终希望将尽量减小在现有应用程序中添加服务所造成的影响。

   服务通常向公司防火墙以外的客户端公开,因此具有不同于业务组件的安全和运行要求。

  与其他服务通信需了解大量与协议和数据格式有关的知识。

  希望将关注的问题分隔在不同的组件中,以便仅针对单个原因而更改组件,例如将业务逻辑与访问外部服务所需的技术分隔开来。  

Layers引进了一个用来组织软件应用程序的基本策略。Three-Layered Application优化了此概念,并将它限制在需要重复使用业务逻辑、灵活部署和高效使用连接的业务系统内。Three-Layered Services Application有在Three-Layered Application的基础上进行了优化,并对设计进行了扩展,以便在提供和使用其来源千差万别的数据和逻辑时,将这些数据和逻辑处理为粒状元素。

  此模式规定的三层是自己的解决方案的良好起点。在继承 Layered Application 模式所具有的大多数优点的同时,还可尽量减少必须跨越过多层所造成的负面影响。

  对于复杂的解决方案,可能有必要进一步划分域层,尤其是在重用性具有很高的优先级,或者要基于常用的一组组件设计一系列解决方案时,更是如此。在这种情况下,通常用下列三层来替换此模式中描述的一个业务层:

  应用程序。应用程序层包含对于应用程序具有唯一性的业务组件。

  域。域层包含业务域内常见的业务组件。例如,与保险、能源或银行业有关的组件。

  业务服务。业务服务层包含提供常用业务功能(如财务、产品和订单功能)的业务组件。

  单一用户界面层对于提供复杂用户界面的解决方案可能不够。例如,数据验证、命令处理、打印和撤消/重复等功能可能需要其他层。

  除了这些分层外还有好多分层方式:

  Brown模型的分层模型,

 

它分为 表现层, 控制层/中介层,业务逻辑层,数据映射层,数据源层。从本质上来看是在三层模式的基础上增加了两个中介层。

           Brown 分层模型                    Fowler                     

          表现层                                  表现层 

       控制层/中介层                     表现层(应用控制器)

      业务逻辑层                          领域层

       数据映射层                          数据源层(数据映射器)

        数据源层                              数据源层


CoreJ2EE patterns

分为客户层,表现层,业务层,集成层和资源层。业务层和集成层存在简单的对应关系,资源层包含了集成层需要连接到的外部服务。主要区别在于它将表现层分成了客户端部分(客户层)和服务器端(表现层)。

        CoreJ2EE patterns                               Fowler

          客户层                              运行于客户端的表现层

          表现层                              运行于服务器端的表现层

         业务层                              领域层

          集成层                              数据源层

            资源层                              需要与数据源层通信的外部资源

Marinescu中使用五层结构

 

表现层被分为两部分,主要反映了应用控制器的分离。领域层也被分为两部分,实际上是在领域模型上构件了服务曾。

      Marinescu                           Fowler 

     表现层                                表现层

     应用层                                表现层(应用控制器)

      服务层                                领域层(服务层)

      领域层                                领域层(领域模型)

      持久层                                数据源层

  将服务层从领域层中剥离出去的原因,源于将工作流逻辑从纯粹领域逻辑剥离。服务层所包含的逻辑一般都特定于某个用例,并与其他一些基础设施相互通信,如消息机制。

  Nilsson模型

 

用来单独的应用层和领域层来表示领域逻辑。小型系统可以不使用领域层。

    Nilsson                                Fowler

     顾客层                                表现层

     顾客帮助层                        表现层(应用控制器)

    应用层                                领域层(服务层)

     领域层                                领域层(领域模型)

    持久访问层                        数据源层

公共存储过程层                数据源层(可能包含一些领域层)

   私有存储过程层                数据源层(可能包含一些领域层)

  总之,所有的分层模式都是根据我们所要建立的企业应用程序的业务复杂程度来决定的。分层模式只是用在应用程序的体系结构上,真正的设计好一个企业应用程序还需要结合其他的设计模式。如何把它们很好的结合在一起需要我们的经验和对模式的理解。以上这些分层模式都是现有的分层模式,这里只是简单的列举出来,希望大家能共同讨论,共同学习,共同进步。                   

posted on 2006-12-12 15:40  ylm㊣  阅读(936)  评论(2编辑  收藏  举报