三层架构

 
将整个业务应用划分为:界面层(User Interface layer, UIL)、业务逻辑层(Business Logic Layer, BLL)、数据访问层(Data access layer, DAL)。
 
 
1:界面层:主要是指用户交互的界面。用于接收用户输入的数据和显示处理后用户需要的数据。如果逻辑层相当强大和完善,无论表现层如何定义和更改,逻辑层都能完善地提供服务。
 
2:业务逻辑层:UI层和DAL层之间的桥梁。实现业务逻辑。业务逻辑具体包含:验证、计算、业务规则等等。
 
3:数据访问层:与数据库打交道。主要实现对数据的增、删、改、查。将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库。(当然这些操作都是基于UI层的。用户的需求反映给界面(UI),UI反映给BLL,BLL反映给DAL,DAL进行数据的操作,操作后再一一返回,直到将用户所需数据反馈给用户)。
 
   

规则

  1. 最关键的,UI层只能作为一个外壳,不能包含任何业务逻辑(BizLogic)的处理过程。只有少量(或者没有)SQL语句或者存储过程的调用,并且这些语句保证不会修改数据。
  2. 设计时应该从BLL出发,而不是UI出发。BLL层在API上应该实现所有BizLogic(以面向对象的方式)。如果把UILayer拿掉,项目还能在Interface/API的层次上提供所有功能)。
  3. 不管数据层是一个简单的SqlHelper也好,还是带有Mapping过的Classes也好,应该在一定的抽象程度上做到系统无关(DAL可以移植到其他类似环境的项目)。
  4. 不管使用COM+(Enterprise Service),还是Remoting,还是WebService之类的远程对象技术,不管部署的时候是不是真的分别部署到不同的服务器上,最起码在设计的时候要做这样的考虑,更远的,还得考虑多台服务器通过负载均衡作集群(三个模块,可以分别运行于不同的服务器)。

优势

1,结构清晰、耦合度低,

2,可维护性高,可扩展性高;

3,利于开发任务同步进行;容易适应需求变化

劣势

1、有时会导致级联的修改。这种修改尤其体现在自上而下的方向。如果在表示层中需要增加一个功能,为保证其设计符合分层式结构,可能需要在相应的业务逻辑层和数据访问层中都增加相应的代码

2、增加了代码量,增加了工作量,增加了复杂度。

MVC

如果说ORM(Object Relation Mapping)等框架是数据访问层的框架模式,解除了业务逻辑和数据之间的耦合,业务逻辑不再关心底层数据如何存储和读取。所有数据呈现给业务逻辑层的就是一个个的对象。

MVC则是表现层的框架模式。用于解除业务逻辑和视图之间的耦合。从而易于扩展,便于测试。

MVC诞生于1979年,体现了“关注点分离”这一设计方针,它将一个人机交互应用涉及的功能分为三部分。

Model

Model对应应用状态和业务功能的封装,可以将它理解为同时包含数据和行为的领域模型(Domain Model)。Model接受Controller的请求并完成相应的业务处理,在应用状态改变的时候可以向View发出相应的通知。

View

View实现可视化界面的呈现并捕捉最终用户的交互操作。View可以直接调用Model查询其状态信息,而Model也可以在自己的状态发生改变时,主动通知View。

Controller

Contoller是M和V之间的连接器,用于控制应用程序的流程。View捕获用户交互操作后直接转发给Contoller,后者完成相应的UI逻辑。如果需要涉及业务功能的调用,Contoller会直接调用Model及修改Model状态。Contoller也可以主动控制原View或创建新的View对用户交互操作予以响应。
 

MVC使用的误区

把Model理解成实体类(Entity)

在MVC中Model应该包含2部分功能,一部分是处理业务逻辑,一部分是提供View显示的数据。

它应该是业务逻辑真正的实现层。所以Model的实际上是Business Model(业务模型)。而Controller仅仅起一个“桥梁”作用,它负责把View的请求转发给Model,再负责把Model处理结束的消息通知View。Controller的存在是为了使UI界面、UI逻辑、业务逻辑之间分离。

大量业务逻辑代码堆积在Controller端

MVC中的控制器,内里封装了通讯,容易变成大而全 的高度耦合的集中器。
  1. 控制器中写业务代码
    1. UI逻辑可以写在Controller中,而业务逻辑应该在Model里,Controller只是去调用它们。
  2. 控制器变得依赖信息数据中心或数据库,对象将间接地通过控制器的action耦合在一起

    1. 可以通过引入IOC容器来解决

总结

MVC最早的定义毕竟是79年提出的,到现在GUI编程环境,业务复杂程度都有了很大改变。当采用MVC模式设计UI应用时,一般会根据开发框架的特点来对Model,View和Contoller设置一个明确的界限,同时为它们之间的交互制定一个更加严格的规则。

MVC变体

在软件发展历程中出现了一些MVC变体,它们遵循定义在MVC中的基本原则,但对三元素直接的交互制定了更为严格的规范。

MVP

  1. MVP适用于基于事件驱动的应用框架中,如Asp.net Web Forms 和Windows Forms应用。
  2. MVP中严格禁止View和Model间的直接交互,必需通过Presenter来完成。Model的独立性得到了真正的体现,它不仅仅与可视化元素的呈现(View)无关,与UI处理逻辑也无关。使用MVP的应用是用户驱动而不是Model驱动,所以Model不需要主动通知view。
  3. MVP模式中的V代表的是一个接口,一个将UI界面提炼而抽象出来的接口。接口意味着任何实现了该接口的界面,都能够复用已有的Presenter和Model代码。是真正意义上的隔离View的细节和复杂性的模式,降低了Presenter对View的依赖。带来的好处就是定义在Presenter中的UI处理逻辑变得易于测试。
 
MVP中Presenter与Model的交互很清晰,仅体现为Presenter对Model的单向调用。而View与Presenter直接的交互方式就成了MVP的核心。按照View与Presenter的交互方式依据View本身的职责范围,Martin Folwer将MVP分为PV(Passive View)和SC(Supervising Contoller)两种模式。

PV

view是难以测试的,通过让它尽可能不涉及UI处理逻辑来使它不需要测试,这就是PV模式的目的。
这意味着需要将View中的UI元素通过属性的形式暴露出来。将所有UI处理逻辑全部定义到Presenter中。定义在IView里的只有属性。

SC

PV需要将View中可供操作的UI元素定义在对应的接口中,对于一些复杂的富客户端应用的View来说,接口成员的数量可能会非常多,这无疑提升了代码量和Presenter的复杂度。
SC则将一些单纯,独立的UI逻辑交由View自身来完成。当然它处理的数据是Presenter实时推送给它的。View尽可能不维护数据状态。定义在IView里的接口尽量只包含方法,且是无返回值的方法(单向传递消息)。
 

Models:

public class Employee
{
public string Id { get; private set; }
public string Name { get; private set; }
public string Gender { get; private set; }
public DateTime BirthDate { get; private set; }
public string Department { get; private set; } public Employee(string id,string name,string gender,DateTime birthDate,string department)
{
Id = id;
Name = name;
Gender = gender;
BirthDate = birthDate;
Department = department;
}
} public class EmployeeRespository
{
private static IList<Employee> employees; static EmployeeRespository()
{
employees = new List<Employee>()
{
new Employee("001","张三","男",new DateTime(1981,8,24),"销售部"),
new Employee("002","李四","男",new DateTime(1981,8,24),"人事部"),
new Employee("003","王五","女",new DateTime(1981,8,24),"人事部")
};
} public IEnumerable<Employee> GetEmployees(string department = "")
{
if (string.IsNullOrEmpty(department))
{
return employees;
}
return employees.Where(e => e.Department == department).ToArray();
}
}

Presenter、IView

public class EmployeePresenter
{
public IEmployeeView View { get; private set; }
public EmployeeRespository Respository { get; private set; } public EmployeePresenter(IEmployeeView view)
{
this.View = view;
this.Respository = new EmployeeRespository();
this.View.DepartmentSelected += OnDepartmentSelected;
} public void Initialize()
{
IEnumerable<Employee> employees = this.Respository.GetEmployees();
this.View.BindEmployees(employees);
string[] departments
= new string[]{
"","销售部","采购部","人事部"
};
this.View.BindDepartments(departments);
} protected void OnDepartmentSelected(object sender, DepartmentSelectedEventArgs args)
{
string department = args.Department;
var employees = this.Respository.GetEmployees(department);
this.View.BindEmployees(employees);
}
} public interface IEmployeeView
{
void BindEmployees(IEnumerable<Employee> employees);
void BindDepartments(IEnumerable<string> departments);
event EventHandler<DepartmentSelectedEventArgs> DepartmentSelected;
}
public class DepartmentSelectedEventArgs : EventArgs
{
public string Department { get; private set; }
public DepartmentSelectedEventArgs(string department)
{
this.Department = department;
}
}

WinForm实现的UI界面

public partial class Form1 : Form, IEmployeeView
{
private EmployeePresenter Presenter{ get; private set; }
public Form1()
{
InitializeComponent(); Presenter = new EmployeePresenter(this);
Presenter.Initialize();
}
public event EventHandler<DepartmentSelectedEventArgs> DepartmentSelected; public void BindDepartments(IEnumerable<string> departments)
{
this.comboBox1.DataSource = departments;
} public void BindEmployees(IEnumerable<Employee> employees)
{
this.listBox1.DataSource = employees;
this.listBox1.DisplayMember = "Name";
} private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string department = (string)this.comboBox1.SelectedItem;
DepartmentSelectedEventArgs eventArgs = new DepartmentSelectedEventArgs(department);
DepartmentSelected?.Invoke(sender, eventArgs);
}
}

WebForm实现的UI界面

public partial class Default : Page, IEmployeeView
{
public EmployeePresenter Presenter { get; private set; }
public event EventHandler<DepartmentSelectedEventArgs> DepartmentSelected; public Default()
{
this.Presenter = new EmployeePresenter(this);
} protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
this.Presenter.Initialize();
}
} protected void ButtonSearch_Click(object sender, EventArgs e)
{
string department = this.DropDownListDepartments.SelectedValue;
DepartmentSelectedEventArgs eventArgs = new DepartmentSelectedEventArgs(department);
if (null != DepartmentSelected)
{
DepartmentSelected(this, eventArgs);
}
} public void BindEmployees(IEnumerable<Employee> employees)
{
this.GridViewEmployees.DataSource = employees;
this.GridViewEmployees.DataBind();
} public void BindDepartments(IEnumerable<string> departments)
{
this.DropDownListDepartments.DataSource = departments;
this.DropDownListDepartments.DataBind();
}
}

在MVP里,可以根据User Story来首先设计和开发Presenter。在这个过程中,View是很简单的,能够把信息显示清楚就可以了。在后面,根据需要再随便更改View, 而对Presenter没有任何的影响了。

如果要实现的UI比较复杂,而且相关的显示逻辑还跟Model有关系,可以在View和 Presenter之间放置一个Adapter。由这个 Adapter来访问Model和View,避免两者之间的关联。而同时,因为Adapter实现了View的接口,从而可以保证与Presenter之 间接口的不变。这样就可以保证View和Presenter之间接口的简洁,又不失去UI的灵活性。

MVVM

MVVM模式中,一个ViewModel和一个View匹配,它没有MVP中的IView接口,而是完全的和View绑定,所有View中的修改变化,都会自动更新到ViewModel中,同时ViewModel的任何变化也会自动同步到View上显示。
这种自动同步之所以能够的原因是ViewModel中的属性都实现了observable这样的接口,也就是说当使用属性的set的方法,都会同时触发属性修改的事件,使绑定的UI自动刷新。(在WPF中,这个observable接口是 INotifyPropertyChanged; 在knockoutjs中,是通过函数ko.observable() 和ko.observrableCollection()来实现的)
在MVP中,V是接口IView, 解决对于界面UI的耦合; 而MVVM则干脆直接使用ViewModel和UI无缝结合, ViewModel直接就能代表UI。但是MVVM做到这点是要依赖具体的平台和技术实现。 这也就是为什么ViewModel不需要实现接口的原因,因为对于具体平台和技术的依赖,本质上使用MVVM模式就是不能替换UI的使用平台的。
MVVM的提出源于WPF,主要是用于分离应用界面层和业务逻辑层。WPF/Siverlight是基于数据驱动开发的。
在MVC和MVP模式中, 开发View层的是程序员, 虽然UI/UE团队会做很多工作, 但这个层的"实现者"仍然是程序员。
而在WPF开发中将View层的代码逻辑抽取出来,并使View层很纯粹以便完全让美工去打造它。相应地, 需要将View层的相应逻辑抽取到一个代码层上,以便让程序员专注在这里。

Asp.net Mvc 应用中的请求处理

  1. 每个HTTP请求的目标是Controller中的一个Action,具体体现为定义在Controller类型中的一个public方法。所以对请求的处理最终体现为对目标Controller对象的激活和对目标Action方法的执行。
  2. Controller的类型和Action方法的名称及作为Action方法的部分参数可以直接通过请求的Url解析出来。
  3. 通过一个拦截器(Interceptor)对抵达Web服务器的HTTP请求进行拦截。这个拦截器根据当前请求解析出目标Controller的类型和对应的Action方法的名称,随后目标Controller被激活,相应的Action方法被执行。
  4. Action方法执行过程中,可以调用Model获取相应的数据及改变其状态。在Action执行的最后阶段一般会创建一个View,后者最终被转换为HTML以HTTP响应的形式返回到客户端。
  5. 绑定在View上的数据称为ViewModel,来源于Model或者基于显示要求进行的简单逻辑计算。它与MVVM中的ViewModel是完全不同的概念,后者不仅包括呈现在View中的数据,也包括数据操作行为。

Asp.Net MVC<一> : 三层架构、MVC的更多相关文章

  1. 转载——Asp.Net MVC+EF+三层架构的完整搭建过程

    转载http://www.cnblogs.com/zzqvq/p/5816091.html Asp.Net MVC+EF+三层架构的完整搭建过程 架构图: 使用的数据库: 一张公司的员工信息表,测试数 ...

  2. Asp.Net MVC简单三层架构(MVC5+EF6)

    三层架构与MVC的关系 三层架构是一个分层式的软件体系架构设计,分为:表现层(UI).业务逻辑层(BLL).数据访问层(DAL).分层的目的是为了实现“高内聚,低耦合”的思想,有利于系统后期的维护.更 ...

  3. mvc和三层架构到底有什么区别

    原文地址:http://zhidao.baidu.com/question/82001542.html?qbl=relate_question_3&word=MVC%20%CA%FD%BE%D ...

  4. MVC和三层架构

    从最开始写程序到现在,一路上听到架构这个词已经无数次了,在工作和圈子里也不停听到大家在讨论它,但是很多时候发现不少人对这个概念的理解都是很模糊的,无意间在知道上看到一个朋友的回答,感觉很不错,特转帖到 ...

  5. 【转】浅谈MVC与三层架构

    首先给大家引入下MVC的概念: MVC(Model View Controller)模型.视图以及控制器,它是一种较为广泛应用的结构设计模式. 模型:就是在MVC设计模式中需要被显示的数据.在通常情况 ...

  6. MVC与三层架构的区别

    我们平时总是将三层架构与MVC混为一谈,殊不知它俩并不是一个概念.下面我来为大家揭晓我所知道的一些真相. 首先,它俩根本不是一个概念. 三层架构是一个分层式的软件体系架构设计,它可适用于任何一个项目. ...

  7. MVC与三层架构

    我们平时总是将三层架构与MVC混为一谈,殊不知它俩并不是一个概念.下面我来为大家揭晓我所知道的一些真相. 首先,它俩根本不是一个概念. 三层架构是一个分层式的软件体系架构设计,它可适用于任何一个项目. ...

  8. 从MVC和三层架构说到SSH整合开发

    相信很多人都认同JavaWeb开发是遵从MVC开发模式的,遵从三层架构进行开发的,是的,大家都这么认同.但是相信大家都会有过这样一个疑问,if(MVC三层模式==三层架构思想)out.println( ...

  9. tornado框架&三层架构&MVC&MTV&模板语言&cookie&session

    web框架的本质其实就是socket服务端再加上业务逻辑处理, 比如像是Tornado这样的框架. 有一些框架则只包含业务逻辑处理, 例如Django, bottle, flask这些框架, 它们的使 ...

  10. jsp&el&jstl mvc和三层架构

    jsp:java在html中插入java 一.JSP技术 1.jsp脚本和注释 jsp脚本:(翻译成servlet,源码位置apache-tomcat-7.0.52\work\Catalina\loc ...

随机推荐

  1. 2014 UESTC暑前集训数据结构专题解题报告

    A.Islands 这种联通块的问题一看就知道是并查集的思想. 做法:从高水位到低水位依序进行操作,这样每次都有新的块浮出水面,可以在前面的基础上进行合并集合的操作.给每个位置分配一个数字,方便合并集 ...

  2. HDU2955 Robberies[01背包]

    Robberies Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  3. [tem]高精度2

    从1开始 ; ; struct big{ int size,d[L]; big():size(a){memset(d,,sizeof(int)*L);} }; void jia(big &a, ...

  4. Google类VR设备知识

    前言 本文所指的google类vr设备是指: 谷歌的Cardboard.三星Gear VR.暴风魔镜等这样的手机VR盒子,而并不是HTC Vive这类. 人眼立体感知能力 人的左右眼看到的东西是有差别 ...

  5. 使用javascript对密码进行有密码强度提示的验证

    好些网站的注册功能中,都有对密码进行验证并且还有强度提示.下面就来实现这种效果.密码强度说明:密码强度:弱——纯数字,纯字母,纯符号密码强度:中——数字,字母,符号任意两种的组合密码强度:强——数字, ...

  6. Oracle日期格式转换

    本文主要介绍Oracle中的日期转换. 1. 日期转化为字符串 (以2016年10月20日为例) select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss')  st ...

  7. ajax之jsonp跨域请求

    前端ajax请求代码 后台php处理代码

  8. HTML 学习笔记 CSS(选择器)

    CSS元素选择器 最常见的CSS 选择器就是元素选择器 换句话说 文档的元素就是最基本的选择器 如果设置HTML样式 选择器通常就是某个HTML元素 比如p h1 em a 甚至可以是HTML本身 h ...

  9. nginx负载均衡集群中的session共享说明

    在网站使用nginx+php做负载均衡情况下,同一个IP访问同一个页面会被分配到不同的服务器上,如果session不同步的话,就会出现很多问题,比如说最常见的登录状态. 下面罗列几种nginx负载均衡 ...

  10. Swift中的Masonry第三方库——SnapKit

    在OC开发时我常用一个名叫Masonry的第三方Autolayout库,在转Swift后发现虽然Swift可以混编OC,但总感觉有些麻烦,在Github上发现了这个叫做SnapKit的第三方库,发现使 ...