[Architecture Design] 3-Layer基础架构

三层式体系结构

只要是软件从业人员,不管是不是本科系出身的,相信对于三层式体系结构一定都不陌生。在三层式体系结构中,将软件开发所产出的程序代码,依照不同用途归类为:系统表示层、领域逻辑层、数据存取层。其中:

  • 系统表示层 (Presentation Layer),用来归类「提供操作接口」的相关程序代码。例如:提供Textbox接受用户输入地址数据、透过MessageBox通知用户处理结果、甚至是提供Web API给远程系统使用,这些程序代码都会被归类在表示层之中。

  • 领域逻辑层 (Domain Layer),用来归类「封装系统逻辑」的相关程序代码。例如:商城系统的商品数据、购物车、对账单,或者是出勤系统的上下班记录、员工数据…等等,这些程序代码都会被归类在领域逻辑层 之中。

  • 资料存取层 (Access Layer),用来归类「实作数据存取」的相关程序代码。例如:将数据存放到SQL Server、或者是从远程WebService取得数据…等等,这些程序代码都会被归赖在存取层之中。

透过三层式体系结构的设计,让开发人员能够粗略的将系统拆解为三个不同面向的分类。透过套用这样的架构设计,在开发过程中,能够减少需要思考的设计内容,让开发人员一次只需要思考某个面向的设计内容。而在后续的维护过程中,也让开发人员能够分门别类的去理解既有的程序内容。

基础架构设计

虽然说,只要是软件从业人员,对于三层式体系结构都不陌生。但是三层式体系结构毕竟是在比较早期的年代所提出,随着面向对象语言的发明、后续DI与IoC概念的加入、以及DDD、TDD等技术的出现。让开发人员在撰写一个套用三层式体系结构的软件系统,需要考虑的方方面面变得越来越多,一层堆一层的知识体系,已经慢慢榨干开发人员的脑细胞活力。不过还好的是,现代的软件业界出现了「软件架构师」这一个职缺。在项目开发的过程中,透过软件架构师的努力,来消化知识体系的堆积,产出为符合项目需求、团队能力的软件架构。后续团队内的开发人员只要照着软件架构去按图施工,就能生产具有一定水平的系统软件。

接下来的内容,介绍一个以三层式体系结构为核心所发展出来的基础软件架构。期望让没有软件架构师加持的开发人员,能有一个基础的软件架构来按图施工,除了增加软件开发的速度之外,也让项目产出的程序代码能够满足:进行单元测试、重用系统逻辑、抽换数据源….等等非功能性需求。

领域逻辑层 (Domain Layer)

接着从三层式体系结构中的领域逻辑层来看看,领域逻辑层所包含的对象该如何设计。领域逻辑层主要用来归类「封装系统逻辑」的相关程序代码,而「系统逻辑」这个概念,可以拆解为几个模式来分门别类的设计:

  • Entity:Entity主要用来将数据单元封装成为对象。在设计系统的时候,一个一个系统要处理的数据单元可以封装成为Entity对象,每个Entity对象的属性则是用来提供数据单元所包含的数据内容,像是上图中的Employee对象、Product对象用来代表系统所要处理的员工数据、商品数据。另外,Entity对象的方法,也用来封装各种运算功能;例如一个判断员工是否成年的功能,就可以选择封装成为Employee对象的方法来提供使用。

  • IRepository:IRepository主要用来定义Entity对象进出领域逻辑层的接口(系统边界)。在设计系统的时候,当有Entity对象需要进出数据库或是远程服务,可以将进出功能封装成为IRepository接口的方法,像是上图中的IEmployeeRepository接口用来提供Employee对象进出系统数据库的方法定义。另外,IEmployeeRepository接口的方法,也用来封装各种查询功能;例如一个查询所有售价少于100元商品的功能,就可以选择封装成为IEmployeeRepository界面的方法来提供使用。

  • Service:Service主要用来封装系统终难以归类的系统功能。在设计系统的时候,当有一个系统功能分派给Entity对象不适合、分派给IRepository接口也不适合的时候,就可以考虑额外将这个系统功能封装为Service对象。例如一个转账功能,可能牵扯好几个帐户、并且需要许多交易纪录,这时分派给Entity对象、IRepository接口会让这两者的耦合度过高,这时就可以选择封装一个独立的转账服务对象来提供使用。

  • Context:Context主要用来提供统一的进入点来使用系统功能。在设计系统的时候,系统功能会被分派到 Entity对象、IRepository接口、Service对象来提供使用,这时加入Context对象将原本四散的职责黏合,能够简化使用时的复杂度。另外一个进阶的议题,是统一由Context对象来提供注入与保存IRepository接口实作,也是一个减少领域逻辑层与DI Framework相依的一种解决方案。

透过上列几个模式来分门别类的设计,基本上就可以将领域逻辑层所要封装的系统逻辑,都建立成为一个个的对象。而套用这样的设计架构,因为透过IRepository接口来建构出系统边界,所以让单元测试得以进行;透过Context对象来简化系统复杂度,让重用系统逻辑、抽换数据源变成可行。

系统表示层 (Presentation Layer)

谈完最核心的领域逻辑层,接着看系统表示层就比较轻松一点了。系统表示层 (Presentation Layer),用来归类「提供操作接口」的相关程序代码,这边所定义的操作接口有一个很重要的概念是,操作接口包含:

  • 给人使用的UI接口:给人使用的UI接口,就是应用程序的用户接口。透过应用程序的所提供的可视化接口,系统就可以提供信息给用户,并且接收用户所输入的数据以及操作。

  • 给系统使用的API接口:给系统使用的API接口,就是服务程序的通讯接口。服务程序提供各种通讯接口来开放功能给外部系统使用,这些接口可能会是WCF、Web Service、甚至是最近很夯的SignalR,都会是系统所提供的API接口的其中一种可选择方案。

回过头综观整个系统表示层的设计,简单说就是对上提供接口给其他人使用,对下依照接口操作去使用领域逻辑层所提供的功能。例如说:领域逻辑层提供了一个「查询所有售价少于100元商品的功能」,当系统提供UI接口给人使用时,可能就会提供一个显示页面来条列所有从资料存取层查询出来的商品;当系统提供API接口给系统使用时,可能就会建立一个Web API的方法来提供查询,并且使用JSON格式来回传所有从数据存取层查询出来的商品。

当然,没有好处的事,我们不要去做。系统中切割出系统表示层,在项目开发的过程中会得到一个很大的好处就是:系统表示层是用户最会修改的设计。做项目时,使用者最会有意见的就是系统表示层,当开发人员将系统表示层独立切割开来,就算画面怎么变化背后的逻辑还是不会变。这样开发人员心理上,就能比较轻松去面对客户的挑战(反正也只是画面调调而已),而实质上因为不会动到核心的领域逻辑层,也避免了改这边坏那边的窘境。

资料存取层 (Access Layer)

最后看看在三层式体系结构中最单纯的数据存取层。数据存取层 (Access Layer),用来归类「实作数据存取」的相关程序代码,这边所定义的实作数据存取,就是很简单的实作领域逻辑层中所定义的IRepository接口。但是虽然说是很简单的实作IRepository接口,却也是包含了许多的变化:

  • 数据存放到数据库(远程):一般的Web网站、应用程序,会选择将数据存放到远程的Sql Server。

  • 数据存放到数据库(近端):在一些APP的开发项目中,会选择将数据存放在本地端的SQLite。

  • 数据存放到系统(远程):在一些APP的开发项目中,会选择将数据透过Web Service存放在远程的服务器上。

  • 数据存放到系统(近端):在一些复杂的开发项目中,会选择数据源是另外一个领域逻辑层。例如:一个购物商城的客户数据源,有可能是由另外一个客户管理系统来提供。

  • 依照运行状态决定:在一些APP的开发项目中,会依照网络联机状态来决定数据存放位置。例如:网络断线时存取本地端的SQLite、网络联机时存取远嘟的WebService。

  • ......

在上列这些可以选择的解决方案中,比较有趣的是数据存放到系统、依照运行状态决定这两个变化样式。其中数据存放到系统这个变化样式,为系统加入了串接各种系统的可能性,让系统能够像堆积木一样,一个串一个的互相结合,大幅增加系统的重用性。而依照运行状态决定,则是一个重用程序代码的设计,只要额外加入一个IRepository实作来判断运行状态,并且分配该去呼叫哪个现有的Sql实作、Web实作,就可以重复使用既有程序。

同样的,没有好处的事,我们不要去做。系统中切割出数据存取层,在项目开发的过程中会得到一个很大的好处就是:数据存取层是开发过程中最会修改的设计。做项目的时候,系统开发的过程中很多数据字段都要到项目中后期客户才会发现(很神奇,但真实)。当开发人员将资料存取层独立切割开来,并且在数据字段定案之前,都先透过对象操作的方式来提供数据,并在最后的最后才去建立SQL数据表。这样在开发的过程中,就不需要反复的调整数据表字段、检查对应的SQL指令,大量减少开发人员花在这些琐碎工作上的时间成本。

下载

范例程序代码:点此下载

[Architecture Design] 3-Layer基础架构的更多相关文章

  1. [Architecture Design] 累进式Domain Layer

    [Architecture Design] 累进式Domain Layer 前言 本篇的内容大幅度的简化了分析设计.面向对象等等相关知识,用以传达累进式Domain Layer的核心概念.实际开发软件 ...

  2. [Architecture Design] 跨平台架构设计

    [Architecture Design] 跨平台架构设计 跨越平台 Productivity Future Vision 2011 在开始谈跨平台架构设计之前,请大家先看看上面这段影片,影片内容是微 ...

  3. [Architecture Design] CLK Architecture

    CLK.Prototype.Architecture 最近找数据,看到了博客园在不久之前,办了一个架构分享的活动:.Net项目分层与文件夹结构大全.看完之后觉得获益良多,接着也忍不住手痒,开始整理属于 ...

  4. b2c项目基础架构分析(二)前端框架 以及补漏的第一篇名词解释

    继续上篇,上篇里忘记了也很重要的前端部分,今天的网站基本上是以一个启示页,然后少量的整页切换,大量的浏览器后台调用web服务局部.动态更新页面显示状态这种方式在运作的,从若干年前简单的ajax流行起来 ...

  5. b2c项目基础架构分析(一)b2c 大型站点方案简述 已补充名词解释

    我最近一直在找适合将来用于公司大型bs,b2b b2c的基础架构. 实际情况是要建立一个bs架构b2b.b2c的网站,当然还包括wap站点.手机app站点. 一.现有公司技术人员现状: 1.熟悉asp ...

  6. 面向服务体系架构(SOA)和数据仓库(DW)的思考基于 IBM 产品体系搭建基于 SOA 和 DW 的企业基础架构平台

    面向服务体系架构(SOA)和数据仓库(DW)的思考 基于 IBM 产品体系搭建基于 SOA 和 DW 的企业基础架构平台 当前业界对面向服务体系架构(SOA)和数据仓库(Data Warehouse, ...

  7. ZT Android4.2蓝牙基础架构学习

    Android4.2蓝牙基础架构学习 分类: Jellybean Bluetooth Bluetooth 2013-10-13 23:58 863人阅读 评论(3) 收藏 举报 androidblue ...

  8. ITIL《信息技术基础架构库》

    一 概述 1. ITIL 自上世纪70年代开始,个人计算机以及计算机网络开始在欧美发达国家普及.随着时间的推移,信息系统的规模越来越大,人们对信息系统的依赖也越来越强.特别是到了80年代,互联网开始普 ...

  9. 2.2 DDD Layers & Clean Architecture DDD分层和简洁架构

    DDD Layers & Clean Architecture DDD分层和简洁架构 There are four fundamental layers of a Domain Driven ...

随机推荐

  1. Win8.1 Metro应用无法联网,提示“无法加载此页面”解决方法!(看红色字体部分)

    Windows 8 Metro Apps使用Proxifier的方法 By Shinichi_Wtn2012-07-05 20:28 在校园里,经常要使用代理上网的方式,Proxifier可以让不支持 ...

  2. 从function前面的!想到的

    最近没事喜欢看看,一些js库的源码,结果发现库前不是加一个!就是加+或者一个(),心中猜出个大概知道这个是让函数自动执行,可是这么多符号达到同一个目的,原理是什么呢,下面做一下剖析: 先从IIFE开始 ...

  3. svn diff excel

    https://github.com/solq360/compareExcel jdk 1.7 可自己编译1.6 每个sheet第一行不允许为空 SVN对比excel差异 适合策划.财务职业使用 sv ...

  4. [原]运行编译好的Android模拟器

    Android源码编译好了之后,我们就可以运行它了. 1.配置环境变量: /data/data/Android$ export PATH=$PATH:$(pwd)/out/host/linux-x86 ...

  5. ThinkJS 项目用 WebStorm 来设置断点与调试

    1. 前置条件.已按ThinkJS 2.0 文档 之 <创建项目> 建好项目. 说明a: 本示例创建项目名为wagang,使用es6配置: thinkjs new wagang --es6 ...

  6. 编译Libgdiplus遇到的问题

    https://github.com/mono/libgdiplus/releases 下载最新版本 解压并执行  ./autogen.sh,在执行此步时遇到如下问题,并帖出解决办法   问题:执行  ...

  7. 【分布式】RPC初探

    事先声明:本文代码参考自Dubbo作者的博客. RPC(Remote Procedure Call)远程过程调用,是分布式系统当中必不可少的一个玩意.比如说在单机系统当中,我想调用某个方法,直接调就可 ...

  8. Android 学习笔记 BroadcastReceiver广播...

    PS:不断提升自己,是件好事... 学习内容: 1.BroadcastReceiver的使用.. 2.通过BroadcastReceiver去启动Service... 1.BroadcastRecei ...

  9. java抽象类和接口区别

    深入理解Java的接口和抽象类 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的 ...

  10. ASP.NET 为GridView添加序号列,且支持分页连续累计显示

    为GridView添加序号列,且支持分页连续累计显示,废话不多说,直接上代码: <%@ Page Language="C#" AutoEventWireup="tr ...