重温经典之《企业应用架构模式》——.NET中的架构模式运用 (Base Patterns 3)

度过了一个不错周末,也买了不少新书,却把这本书被搁置了几天,今天继续。

Special Case模式

         Special Case是一种在面向对象设计中很常用的模式,面向对象的系统一个很重要的特性就是多态性,为每一种具体的情况设计一种对象来应对,则是所谓的Special Case

         既然是Special,也就是特殊,所以我们重点照顾的,也就是边缘情况。最常见的边缘情况就是null了。将null替换成Special Case也就是特殊情况对象,是一种非常常用的Special Case用法。

         在大多数面向对象的编程语言中,我们经常持有对象的引用而不是对象本身,这样就有了引用无效的情况,也就是出现了null。你可以现象一下在代码中你写过多少类似 if (xxx != null) 这样的代码,为了程序的健壮,也为了让自己对自己的程序放心,我们经常会在程序中做这样的判断。

         例如这样的代码:

            Person person = FindPersonByName("Yannic");

            if (person != null)

            {

                Console.WriteLine(person.Name);

        }

这种对对象非空判断是必要的,但是我们思考下面这几个问题:

         1 是不是每次调用对象我们都要做一个非空判断呢?那样的话程序中岂不是充斥了”xxx != null”这样的代码吗?

         2 如果不是,那么到底什么时候要判断非空,什么时候不需要判断呢?上面的例子对于非空的判断完全可以放在FindPersonByName方法内,但是,谁又敢依赖这个函数呢?

         3 如果真的是null,如何处理?

 

         其实自己在写代码的时候往往真的是在凭一时的感觉决定是不是要进行一个非空的判断,怪不得程序老出现“缺少对象引用”那样的错误,光凭感觉太容易遗漏了。

         于是我们引入Special Case,定义一个对象来表示Null。例如本来我们要处理的是Person对象,这里就直接定义一个NullPerson对象,并继承Person,以后再出现需要返回空结果的时候,我们直接返回NullPerson

Code

         调用代码就不需要做判断了:

           Person person = FindPersonByName("Yannic");

            Console.WriteLine(person.Name);

         我们从面向对象的角度来分析一下这种做法。本来对于null的判断分散在代码各处,大家各自为战,以至于各自的处理方式都不同。

         为了改善这种情况,我们定下规矩,调用代码不做判断,完全依赖上层代码,也就是例子里的FindPersonByName方法。

         这样把责任抛给了FindPersonByName,也就形成了一种对上层代码的依赖,但是,有一天这个函数不可靠,那一切都完了。这很容易发生,比如用户新添加其他代码时,也许他就不知道应该承担判断是否为null的责任。

         于是我们使用了Special Case,本质上,我们把判断是否为空的责任独立开来,丢给了NullPerson对象和面向对象系统。

         这也就是Special Case的本质,分离职责。

 

想啊想,除了Double.PositiveInfinity或者DateTime.MinValue这类简单的例子之外,还真没想到太好的例子。相对的说来,我觉得DateTime.MinValue作为例子更合适一些吧,大家慢慢体会。如果想到更好的例子,欢迎随时告诉我……

 

Plugin模式

         前面提到过Separted Interface模式也就是使用接口,使用接口固然可以分离实现和声明分开,但接口一多,整个程序依然会变得有些杂乱无章,毕竟接口在使用前是要被具体实现的。其实将接口的具体实现与使用挂钩的这个过程,我们也完全可以将它独立开来,这有些类似工厂模式,不过各种工厂模式强调类的创建,而在这里更加强调为已经定义好的一系列接口提供实现。

         最常见也用的最多的方法,就是把装配所需要信息写在配置文件中,这样整个装配就灵活得多。

C#,Java这些高级的面向对象编程语言中,反射功能让这个装配的过程变得非常简单和好用(虽然效率没那么高),下面直接看看ASP2.0中最经典的MembershipProvider吧。

对于用户来说,定义一个Provider是多么的简单,只需要在web.config文件里添加类似这样的XML:

       <membership defaultProvider="SQLMembershipProvider">

           <providers>

              <add name="SQLMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="SQLMembershipConnString" applicationName=".NET Pet Shop 4.0" />

           </providers>

       </membership>

系统在运行期,读取配置文件中的字符串,然后通过字符串去取得某些类,装配到应用程序中。

 

小记

Base Pattern还有Server StubRecordSet两种,Server Stub类似.NET中生成的服务代理类,而RecordSet类似DataReader,暂时就不写了。

下面的计划是重新研究一下界面层的MVC模式,MVC模式是很重要的一大块东西。界面显示是软件开发不可能逃避的问题,不论在WinFormASP.NETasp.net ajax还是WPF中都有各种类似又不同的界面实现,这些不同实现可以说思想都来自于MVC模式,但是都又和标准的MVC模式不同。

之后几天我要解决的问题,就是从最基本的MVC模式开始,去研究到底什么是MVC模式,.NET框架中又是如何实现他们的,同时做了哪些改良。

posted on 2008-09-09 17:17  Yuxin Yang  阅读(651)  评论(0编辑  收藏  举报