1、 三层架构

 
将整个业务应用划分为:界面层(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.1、 规则

  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、 优势

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

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

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

1.3、 劣势

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

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

2、 MVC

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

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

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

2.1、 Model

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

2.2、 View

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

2.3、 Controller

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

2.1、 MVC使用的误区

2.1.1、 把Model理解成实体类(Entity)

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

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

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

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

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

2.2、 总结

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

3、 MVC变体

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

3.1、 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)两种模式。

3.1.1、 PV

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

3.1.2、 SC

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

Models:

public class Employee

{
    public string Id { getprivate set; }
    public string Name { getprivate set; }
    public string Gender { getprivate set; }
    public DateTime BirthDate { getprivate set; }
    public string Department { getprivate 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 { getprivate set; }
    public EmployeeRespository Respository { getprivate 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 { getprivate set; }
    public DepartmentSelectedEventArgs(string department)
    {
        this.Department = department;
    }
}
WinForm实现的UI界面
public partial class Form1 : Form, IEmployeeView

{
    private EmployeePresenter Presenter{ getprivate 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 { getprivate 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的灵活性。

3.2、 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层的相应逻辑抽取到一个代码层上,以便让程序员专注在这里。

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

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



转载自:http://www.cnblogs.com/wj033/p/5812938.html

架构 : 三层架构、MVC、MVP、MVVM的更多相关文章

  1. Android App的设计架构:MVC,MVP,MVVM与架构经验谈

    相关:http://www.cnblogs.com/wytiger/p/5996876.html 和MVC框架模式一样,Model模型处理数据代码不变在Android的App开发中,很多人经常会头疼于 ...

  2. Android App的设计架构:MVC,MVP,MVVM与架构AAAAA

    1. 架构设计的目的1.1 通过设计使程序模块化,做到模块内部的高聚合和模块之间的低耦合.1.2 这样做的好处是使得程序在开发的过程中,开发人员只需要专注于一点,提高程序开发的效率,并且更容易进行后续 ...

  3. [转]MVVM架构~mvc,mvp,mvvm大话开篇

    MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负 责显示.作为一种新的模式,MVP与MVC有着一 ...

  4. 前端mvc mvp mvvm 架构介绍(vue重构项目一)

    首先 我们为什么重构这个项目 1:我们现有的技术是前后台不分离,页面上采用esayUI+jq构成的单页面,每个所谓的单页面都是从后台胜场的唯一Id 与前端绑定,即使你找到了那个页面元素,也找不到所在的 ...

  5. android MVC && MVP && MVVM分析和对比

    相关:http://www.cnblogs.com/wytiger/p/5305087.html 出处http://blog.csdn.net/self_study,对技术感兴趣的同鞋加群544645 ...

  6. MVC, MVP, MVVM比较以及区别(上)

    MVC, MVP和MVVM都是用来解决界面呈现和逻辑代码分离而出现的模式.以前只是对它们有部分的了解,没有深入的研究过,对于一些里面的概念和区别也是一知半解.现在一边查资料,并结合自己的理解,来谈一下 ...

  7. MVC, MVP, MVVM比较以及区别

    MVC, MVP和MVVM都是用来解决界面呈现和逻辑代码分离而出现的模式.以前只是对它们有部分的了解,没有深入的研究过,对于一些里面的概念和区别也是一知半解.现在一边查资料,并结合自己的理解,来谈一下 ...

  8. [1] MVC & MVP &MVVM

    开发架构之MVC & MVP & MVVM  

  9. 浅析前端开发中的 MVC/MVP/MVVM 模式

    MVC,MVP和MVVM都是常见的软件架构设计模式(Architectural Pattern),它通过分离关注点来改进代码的组织方式.不同于设计模式(Design Pattern),只是为了解决一类 ...

  10. 用户界面编程模式 MVC MVP MVVM

    用户界面编程模式 MVC MVP MVVM 程序 = 数据 + 算法 数据:就是待处理的东西 算法:就是代码 涉及到人机交互的程序,不可避免涉及到界面和界面上显示的数据原始方式是界面代码和逻辑代码糅合 ...

随机推荐

  1. 理解Netty中的零拷贝(Zero-Copy)机制【转】

    理解零拷贝 零拷贝是Netty的重要特性之一,而究竟什么是零拷贝呢? WIKI中对其有如下定义: “Zero-copy” describes computer operations in which ...

  2. 采用alluxio提升MR job和Spark job性能的注意点

    1. 介绍 2. 实验说明 2.1 实验环境 2.2 实验方法 2.3 实验负载 3. MapReduce on alluxio 3.1 读取10G文件(1G split) 3.2 读取20G文件(1 ...

  3. 【C/C++】struct探索·extern "C"含义探索 ·C++与C的混合编程·C 语言高效编程的几招

    本文为笔者阅读<嵌入式C精华>的摘录,推荐一下,不错的书 一.C/C++语言 struct深层探索 1.自然对界 struct是一种复合数据类型,其构成元素既可以是基本数据类型(如 int ...

  4. 说说Python程序的执行过程

    1. Python是一门解释型语言? 我初学Python时,听到的关于Python的第一句话就是,Python是一门解释性语言,我就这样一直相信下去,直到发现了*.pyc文件的存在.如果是解释型语言, ...

  5. qs文档翻译

    安装: npm install qs --save-dev 基本用法: let qs = require('qs'); let assert = require('assert'); //qs.par ...

  6. CSS网页布局中易犯的30个小错误

    即使是CSS高手,也难免在书写CSS代码的时候出一些小错误,或者说,任何一种代码都是如此.小错误却往往造成大问题,浪费很多无辜的时间来调试和排错.查看下面这份CSS网页布局中易犯的10个小错误,努力的 ...

  7. JAVA-JSP内置对象之session范围

    相关资料:<21天学通Java Web开发> session范围1.就是指客户浏览器与服务器一次会话范围内,如果和服务器断开连接,那么这个属性也就失效了.2.通过使用session的set ...

  8. python matplotlib 画图

    import numpy as np import matplotlib.pyplot as plt from pylab import * numpy 常用来组织源数据: 使用 plot 函数直接绘 ...

  9. 微服务之springCloud-docker-feign-hystrix-ribbon(七)

    简介 在上一节中,我们讨论了feign+hystrix在项目开发中,除了考虑正常的调用之外,负载均衡和故障转移也是关注的重点,这也是feign + ribbon+hystrix的优势所在,本节我们就讨 ...

  10. php使用正则函数使用详解

    1. int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, in ...