谈.net开发人“.NET研究”员应该熟悉的开发模式

  我们总会有这样一个经验:一个系统最不容易也最不应该变化的部分是领域逻辑,最容易变化也最应该变化的是数据的呈现方式。

  在java的各种应用中可以说是到处可见mvc,j2ee贯穿mvc的概念,android的开发方式也是类mvc的,mvc结构对于做过java应用的人而言简直就是司空见惯。而在.net这边,由于之前微软为大家提供的各种winform、asp.net项目典范(比如那个petshop series)将“三层”概念很好的灌输到了.net程序员的大脑中,许多.net开发者凡是做个东西都要搬出自己最拿手的IModel、IDAL这样的神器。

  其实mvc与所谓的“三层架构”是两个层次上的东西,前者是一种结构模式,而后者则是分层的角度去说。

  一件很奇怪的事情,许多人知道“三层”却不知道mvc,其实这要归结与.net的早期开发技术asp.net和winform这些page controller的典范让许多人对三层夸夸其谈却对mvc视而不见甚至一无所知。什么是page controller模式呢?搞.net的大多都用过winform和webform,这种xxxform用起来很直观,我们想要做一个程序,ok,最简单的方式就是拖拖拽拽几个控件,然后在一个叫code behind的东西里写这些UI事件的处理逻辑,加一大堆变量用于记录数据和状态,这样一个程序就能出炉。这种开发方式对于一些小软件系统的开发其实效率还是蛮高的,后来人们看到其弊端---一旦修改UI,事件处理就要跟着变,但是业务还是那个业务,凭什么要修改非UI的代码?于是有人提出“三层”,最朴素的理解就是将原本那堆事件处理里的code分成业务代码和数据库访问代码并转移到其它类中,做多了就把那坨UI叫做UI,那坨业务代码叫做BLL,那坨DAO叫做DAL。也就是这种架构:

  而对于j2ee的开发者来说熟悉的是下图。 

  (说明:这两幅图copy自是daxnet文)

  MVC是什么

  MVC是一个很经典的结构,并且其又其思想衍生出很多变种比如MVP,MVVP。传统的MVC结构之一是这样的(拿主动型mvc来说):

  比如web开发(比如asp.net mvc或者是java的web开发方式),view就是纯web页面或者webservice,当提交一个表单/调用webservice或者ajax后会将数据提交给controller(当然期间可能会经过各种filterchain、listener这样的东西)controller调用相应的业务模块来处理这个请求,最终结果会更新View的显示。

  MVP

  对于非天然mvc的框架

  对于asp.net/winform而言,虽然可以通过改造让其支持mvc结构的开发(比如通过定制IHttpModule、IHttpHandler云云),但是在企业看来这些都算是邪门武功(因为这样会丧失xxxform在开发上的很多特性比如快速开发)。大多数使用的是mvp模式。什么是mvp呢?其实mvp是mvc的一个变种。因为用winform或者webform的话form始终是个阻碍mvc开发的问题。那么好,我们仍然使用designer和codebehind,其实一个架构设计的好坏是取决于人而不是具体的技术的,只要我们OO一时强page controller一样好用。

  在MVP模式中我们需要自己定制各个View(web页面或者窗体)对应的IView和IPresenter、IModel。IView要对IPresenter暴露操作UI、数据绑定的接口,IPresenter对IView要暴露当UI事件触发需要调用的接口,IPresenter根据IView传递过来的请求调用业务接口并根据结果操作UI。举个简单的例子,一个计算“x+y=?”的程序。如果我们这样定义IPresenter和IView


public interface IPresenter
{
IView View { get; set; }
void CalculateResult();
}

public interface IView
{
IPresenter Presenter { get; set; }
void ShowResult(string result);
int ValueOne { get; }
int ValueTwo { get; }
}

  IPresenter的实现如下(这里从简把IModel去掉了)

Presenter

namespace ClientLibrary
{
    public class Presenter : IPresenter
    {
        private IView _view;
        public IView View
        {
            get
            {
                return _view;
            }
            set
            {
                _view = value;
                _view.Pr上海网站建设esenter = this;
            }
        }

        private static readonly string RESULT_FORMATTER = "{0}+{1},the result is {2}";
        public void CalculateResult()
        {
            if (_view != null)
            {
                var result = string.Format(RESULT_FORMATTER, _view.ValueOne, _view.ValueTwo, _view.ValueOne + _view.ValueTwo);
                _view.ShowResult(result);
                this.A = 123;
            }
        }
        private int _a;
        public int A
        {
            set
            {
                A = value;
            }
        }
    }
}

View的实现如下(那silverlight为例,换成别的也行)

MainPage

namespace debug
{
    public partial class MainPage : UserControl, IView
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private IPresenter _presenter;

        private void btn_Click(object sender, RoutedEventArgs e)
        {
            if (_presenter != null)
            {
                _presenter.CalculateResult();
            }
            #region hidden
            /*int total = 0;
            try
            {
                total = int.Parse(tb1.Text) + int.Parse(tb2.Text);
                MessageBox.Show("计算结果:" + total.ToString());
            }
            catch (Exception ex)
            {
                MessageBox.Show("出错啦" + ex.ToString());
            }
            finally
            {
                tb1.Text = string.Empty;
                tb2.Text = string.Empty;
            }*/
            #endregion

        }

        public IPresenter Presenter
        {
            get
            {
                return _presenter;
            }
            set
            {
                _presenter = value;
            }
        }

        public void ShowResult(string result)
        {
            MessageBox.Show(result);
        }

        public int ValueOne
        {
            get { return int.Parse(tb1.Text); }
        }

        public int ValueTwo
        {
            get { return int.Parse(tb2.Text); }
        }
    }
}

  一个很简单的东西,看上去写成的要多些那么一坨东西,但是好处是显而易见的,就是更换view非常方便,根本不用去改你的IPresenter、Presenter和业务。一切都是接口调用而不依赖具体实现,这就是好处。

  你必须要懂的MVVM

  对于.NET平台的开发人员,托微软的福分我们拥有一种更为强大的模型---MVVM。这应该算是做WPF/Silverlight应用的人必懂的一种结构,WPF/silverlight天生支持数据绑定和命令绑定(不过sl在命令绑定上还比较弱),这就为我们使用MVVM创造了可能。

  View是什么呢,纯的View只有xaml或者附带必要的只与View本身相关逻辑代码。ViewModel,你可以把它理解为View具体呈现内容所依赖数据的一个抽象,在MVVM中View与ViewModel总会有一种绑定关系,一旦ViewModel中被绑定的数据发生改变View上的数据就会跟着变,相反也有可能,比如你的账号密码框内容发生变化,关联的ViewModel中的数据就会被框架自动通知到。

  在wpf/silverlight中,绑定是通过xaml语法来完成(虽然你可以选择用c#来写但不符合mvvm的宗旨),并且绑定双方的通知机制是有框架来完成,也就是说一个会xaml和blend的美工只需事先和coder商量下“咱们的xx和xx是在哪个ViewModel上叫XXX的属性的XXX属性……”问题之后就可以各干各的了。那么ViewModel怎么写,咋view中又怎么绑定到viewmodel呢?首先我们谈ViewModel。

  说道ViewModel你需要知道依赖属性和依赖对象的概念,这是wpf/silverlight的基础所以不多说。有两种方式写ViewModel。第一种是自己去实现INotifyPropertyChanged接口,并在属性变化时去调用NotifyPropertyChanged事件。

  为了方便我们定义一个ViewModelBase的抽象基类,然后让其他ViewModel继承这个基类。

ViewModelBase

public abstract class ViewModelBase : System.ComponentModel.INotifyPropertyChanged, IDisposable 
    { 
        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; 
        protected void OnPropertyChanged(string propertyName) 
        { 
            if (PropertyChanged != null) 
            { 
                var arg = new System.ComponentModel.PropertyChangedEventArgs(propertyName); 
                PropertyChanged(this, arg); 
            } 
        } 
        public virtual void Dispose() 
        { 
           
        } 
    }


DemoViewModel

public class DemoViewModel : ViewModelBase
    {
        #region fields
        private string _propertyA;
        #endregion
        #region presentation properties
        public string PropertyA
        {
            get
            {
                return _propertyA;
            }
            set
            {
     上海企业网站制作           if (_propertyA != value)
                {
                    _propertyA = value;
                    base.OnPropertyChanged("PropertyA");
                }
            }
        }
        #endregion
    }

  第二种是利用DependencyObject和DependencyProperty。

PeopleItemViewModel

public class PeopleItemViewModel : DependencyObject, IPeopleItemViewModel
    {
        public PeopleItemViewModel()
        {
            
        }
        public static readonly DependencyProperty SimpleUserDataProperty = DependencyProperty.Register("SimpleUserData", typeof(SimpleUserData), typeof(PeopleItemViewModel));
        public static readonly DependencyProperty RelativeSimpleUserDataProperty = DependencyProperty.Register("RelativeSimpleUserData", typeof(ObservableCollection<SimpleUserData>), typeof(PeopleItemViewModel));
        public static readonly DependencyProperty AllSimpleUserDataProperty = DependencyProperty.Register("AllSimpleUserData", typeof(ObservableCollection<SimpleUserData>), typeof(PeopleItemViewModel));

        p上海闵行企业网站制作ublic SimpleUserData SimpleUserData
        {
            get
            {
                return (SimpleUserData)base.GetValue(SimpleUserDataProperty);
            }
            set
            {
                if (!base.CheckAccess())
                {
                    Dispatcher.Invoke(new Action(
                        () =>
                        {
                            SimpleUserData = value;
                        }));
                }
                else
                    base.SetValue(SimpleUserDataProperty, value);
            }
        }
        public ObservableCollection<SimpleUserData> RelativeSimpleUserData
        {
            get
            {
                return (ObservableCollection<SimpleUserData>)base.GetValue(RelativeSimpleUserDataProperty);
            }
            set
            {
                if (!base.CheckAccess())
                {
                    Dispatcher.Invoke(new Action(
                        () =>
                        {
                            RelativeSimpleUserData = value;
                        }));
                }
                else
                {
                    base.SetValue(RelativeSimpleUserDataProperty, value);
                    var collectionView = CollectionViewSource.GetDefaultView(value);
                    collectionView.SortDescriptions.Add(new SortDescription("Distance", ListSortDirection.Ascending));
                }
            }
        }
        public ObservableCollection<SimpleUserData> AllSimpleUserData
        {
            get
            {
                return (ObservableCollection<SimpleUserData>)base.GetValue(AllSimpleUserDataProperty);
            }
            set
            {
                if (!base.CheckAccess())
                {
                    Dispatcher.Invoke(new Action(
                        () =>
                        {
                            AllSimpleUserData = value;
                        }));
                }
                else
                {
                    base.SetValue(AllSimpleUserDataProperty, value);
                    var collectionView = CollectionViewSource.GetDefaultView(value);
                    collectionView.SortDescriptions.Add(new SortDescription("Distance", ListSortDirection.Ascending));
                }
            }
        上海闵行企业网站设计与制作}
}

  在View中绑定ViewModel。

  为了方便,我们可以在app.xaml中将需要的viewmode放到全局资源字典中。

  然后再我们的vs视图设计器Properties(中文版显示的是“属性”)页上选择为绑定源设置绑定目标(包括source和path等)以及必要的值转换器等等即可。

  (PS:虽然vs很强大,但个人还是建议熟悉xaml的绑定语法,想当初用vs2008搞wpf的时候貌似还没有这么方便的设计器。。。)

时间: 2024-09-28 15:25:30

谈.net开发人“.NET研究”员应该熟悉的开发模式的相关文章

谈.net开发人员应该熟悉的开发模式

我们总会有这样一个经验:一个系统最不容易也最不应该变化的部分是领域逻辑,最容易变化也最应该变化的是数据的呈现方式. 在java的各种应用中可以说是到处可见mvc,j2ee贯穿mvc的概念,android的开发方式也是类mvc的,mvc结构对于做过java应用的人而言简直就是司空见惯.而在.net这边,由于之前微软为大家提供的各种winform.asp.net项目典范(比如那个petshop series)将"三层"概念很好的灌输到了.net程序员的大脑中,许多.net开发者凡是做个东西

也谈“为什么中国的程序员总被称为码农?”

        我经常在CSDN上浏览新闻,同时也喜欢阅读博客.最近,我看到有不少文章在谈"为什么中国的程序员总被称为码农"这个话题.大家虽然各抒己见,但都在表明一个事实:在中国做程序员真的很累,与种地的农民没有什么区别.        作为一个刚工作不久的程序员新手,我想就自己的经历谈一下对这个话题的认识.        在学校的时候,我们对那些"IT界的英雄"很是敬佩,包括:盖茨.乔布斯.扎克伯格,以及大家都很熟悉的李开复老师.想到他们用自己的智慧改变了人类的生

再谈“我是怎么招聘程序员的”(下)

原文链接:http://coolshell.cn/articles/4490.html <<<再谈"我是怎么招聘程序员的"(上) 在上篇中,我们说到了一些认识人的方法(操作,知识,经验,能力),还有一些面试的方法(算法题,实际生产活动中的挑战),下面我们来说说,面试的风格,还有一些点评. 把应聘者当成你的同事 有些公司的面试官,在面试过程中问你一个算法题,然后等着你解答了,如果你给出一个答案,然后就会问你有没有更好的答案,如果你给出了正确的答案,他们就会问你一个更难的

安全专家浅谈恶意代码的研究分析(1)

[51CTO.com 专家特稿]国外著名的某安全公司指出:2007年互联网上传播的有记载的新型恶意程序(包括病毒,蠕虫,木马等)数目达2,227,415个,同2006年的结果(535,131个)相比翻升了四倍,恶意软件总数量达到354GB.许多反病毒专家 认为这些恶意软件的急速增加已经达到了一种很极 端的情况.恶意软件的 快速发展.广泛传播,以及新型化. 复杂化,使得展示出更强的破坏性和更多样的传播方式.2008年安全公司对于恶意软件的分析研究也将面临更大的挑战.叶子在本篇文章中将带领大家初步了

.NET简谈构件系统开发模式

在本人的".NET简谈插件系统开发模式"一文中我们详细介绍了插件系统开发模式的优越性,尽管.NET平台或者第三方提供的平台都为我们实现了底层插件原理模型,我们可以在上面进行开发,作为一名有求知欲的程序员才是一名合格的程序员:我们不能满足系统为我们提供的功能,我们要向下沉,沉的越深越好,躲开那些应用变化给我们带来的劳累感,所以我们是否需要掌握一些别人不会的技术,才能让我们在众多的程序员中脱颖而出呢:[王清培版权所有,转载请给出署名] 我们今天来探讨"构件"系统开发模式

谈前后端分离开发模式

前后端分离的开发模式,原本觉得没什么稀奇的玩艺,在最近参与的一个大型项目中,让我有了更深的理解. 前后端分离的开发模式:系统分析阶段,系分和前端开发人员约定好页面上所需的逻辑变量,进入功能开发阶段,前端开发人员进行前台页面结构,样式,行为层的代码编写,并根据约定好的变量,逻辑规则,完成不同情况展示不同的表现.而后端开发人员,只需要按照约定,赋予这些变量含义,并提供前后端交互所需要的数据即可. 以前自己在php上玩过mvc开发框架,但是没有在这么大型的项目中实践过,所以过程中暴露出一些问题,也说明

如何让程序员更容易的开发Web界面?重构SmartAdmin展示TinyUI框架

序言 如何让程序员更容易的开发Web界面,是一个持久的话题,所有的从事相关开发的公司都会碰到这个问题,并且被这个问题所深深困扰. Tiny框架也不得不直视这个问题,确实来说,想解决这个问题,也是非常有难度与深度的,业界也有各种各样的尝试,这也是有各种各样不同框架出现的原因. Tiny框架构建者认为,完全采用一种框架解决所有问题,是不现实的.而且即使目前找得到一种非常好的框架,暂时可以满足应用需要,但是随着技术的发展,业务的进化,就会慢慢变得不再满足业务需要.因此,Tiny框架构建从不再把做一套U

浅谈情感营销与社会化媒体营销手段相结合的新模式

中介交易 SEO诊断 淘宝客 云主机 技术大厅 问世间情为何物?直教人生死相许! 万事万物皆从"情"字出发. 纵然古往今来.千山万水.物是人非--也总是会有才下眉头,却上心头的情愫. 又有谁真能做到挥一挥衣袖,不带走一片云彩呢?! 倘若心有灵犀一点通,更是乐得不知魏晋了. 你都和谁谈过恋爱? 高富帅的?还是理工男? 青梅竹马的?还是暮然回首的? 落花流水的?还是爱到不能爱呢? 就算在选择中都出现过,但是, 你和消费者谈过恋爱吗? 你知道怎样让消费者爱上你吗? 因为爱 所以爱 --浅谈情

《SAP HANA平台应用开发》—第2章2.1节熟悉HANA开发环境

第2章 熟悉HANA开发环境 在第1章中,笔者介绍了SAP HANA的基本概念及其主要服务器端的组件.本章将使用SAP HANA工作台软件登录到一个SAP HANA系统,并快速了解SAP HANA的一些常用操作.主要内容包括:第一次连接到SAP HANA系统,创建Schema.表.视图,使用SQL Console,导入数据等,创建用户,赋予角色,以及在不同的视角下进行切换,进入不同的操作模式等.2.1 环境准备2.1.1 SAP HANA服务器软件及硬件 开展SAP HANA项目或者实施SAP系