面向对象编程(Object Oriented Programming)概念及延伸(三)

    昨天我发布了该系列文章的第二部分,今天我将做第三部分的总结,这也是该系列的最后一个部分,希望能写的更有质量些。

3.17 什么是多态(Polymorphisms)?

        多态是个专用的术语,它的意思是‘很多样子’(many shapes)。更精确的将,多态是种能力,通过这种能力相同的操作可以广泛地应用于不同类型的事物。

       在OOP中,多态是通过很多不同技术实现的,它们分别是方法重载(method overloading)、运算符重载(operator overloading)以及方法覆盖(method overriding)实现的。在下面的内容中我将对它们逐一进行介绍。

3.18 什么是方法重载(method overloading)?

        方法重载简单的说就是在类中定义具有相同名称多种方法。每个类成员都有一个唯一的签名,方法签名由方法名称、类型形参的个数及其每个形参(按从左到右的顺序)的类型和种类(值、引用或者输出)组成,只要签名不同,就可以在类中定义具有相同名称的多种方法。例如下面的代码示例:

        public class Test

        {

                void F() { … }                       //F()

                void F(int x) { … }                 //F(int)

                void F(ref int x) { … }            //F(ref int)

                void F(out int x) { … }           //F(out int),错误

                void F(int x, int y) { … }        //F(int, int)

                int F(string s) { … }              //F(string)

                int F(int x) { … }                   //F(int), 错误

                void F(string[] a) { … }         //F(string[])

                void F(params string[] a)       //F(string[]),错误

        }

        我们来仔细分析一下上面的例子,由于ref和out参数修饰符都是方法签名的一部分,因此F(int)和F(ref int)这两个签名都有唯一性,但是F(ref int)和F(out int)不能在同一个类中进行声明,因为尽管ref和out在运行时的处理方式不同,但它们在编译时的处理方式是相同的。因此,如果一个方法采用ref参数,而另一个方法采用out参数,则无法重载这两个方法。此外返回类型和params修饰符不是签名的组成部分。不能仅基于返回类型或是否存在params修饰符来实施重载,因此上面列出的关于方法F(int)和F(params string[])的声明会导致编译时错误。

3.19 什么是运算符重载(operator overloading)?

        运算符重载(通常很少人知道它是ad-hoc多态)是一种特殊的多态,在运算符重载中,像运算符+、-或者==将会有多态的功能,它们将根据参数的不同的类型而产生不同的行为。下面是运算符重载的一个例子:

        public class Complex

        {

                private int real;

                public int Real

                { get { return real; } }

 

                private int imaginary;

                public int Imaginary

                { get { return imaginary; } }

 

                public Complex(int real, int imaginary)

                {

                        this.real = real;

                        this.imaginary = imaginary;

                }

                public static Complex operator +(Complex c1, Complex c2)

                {

                        return new Complex(c1.real+c2.real, c1.Imaginary + c2.Imaginary);

                }

        }

        上面的例子中我们对加号进行了运算符重载,重载后它将可以进行两个complex对象的成员相加。

3.20 什么是方法覆盖(Method Override)?

        方法覆盖是一种语言的特性,它允许子类覆盖父类提供方法的实现。

        子类需要给出自己的方法定义,但是它的签名要和父类的方法一样。这也就是说,当进行覆盖时,子类的方法应该具有和父类被覆盖方法一样的名称和参数列表。下面是方法覆盖的例子:

        public class Complex

        {

                private int real;

                public int Real

                { get { return real; } }

 

                private int imaginary;

                public int Imaginary

                { get { return imaginary; } }

 

                public Complex(int real, int imaginary)

                {

                        this.real = real;

                        this.imaginary = imaginary;

                }

                public static Complex operator +(Complex c1, Complex c2)

                {

                        return new Complex(c1.real+c2.real, c1.Imaginary + c2.Imaginary);

                }

                public override string ToString()

                {

                        return (String.Format(“{0}+{1}”, real, imaginary));

                }

        }

        在上面的例子中我们通过在运算符重载下增加了一个方法扩展了Complex这个类。这个类包含一个覆盖的方法,名字是“ToString”,它重写了默认的“ToString”方法的实现。通过以下代码可以进行测试:

        Complex num1 = new Complex(5, 7);
        Complex num2 = new Complex(3, 8);

        //在这里用到了运算符重载后的加法 

        Complex sum = num1 + num2;

        // 使用覆盖的ToString方法
        Console.WriteLine("({0}) + ({1}) = {2}", num1, num2, sum);
        Console.ReadLine();

3.21 什么是用例(Use case)?

        用例就是文本形式的情节描述,广泛地应用于需求的发现和记录工作中。一个用例可以说是参与者通过系统交互而实现的一个情节,一个用例将参与者和系统功能进行映射。有一点很重要的是,参与者不一定是实实在在的人本身。举个例子说,当系统与别的系统通信的时候,它也可以充当一个角色和参与者。下图是一个用例图:

usercase1 图1 用例图

        在另一个角度看,用例将用户和系统的交互表示了出来,它的特点是:

        (1)捕捉用户可见的功能;

        (2)获得用户明确的需求。

        一个完整用例将很大程度上定义了系统的需求:所有用户可见的信息以及用户可以通过系统做些什么。下面是个用例图描述了登陆模块:

usecaseLogin图2 登陆模块用例

3.22 什么是类图(Class Diagram)?

        类图广泛地被用于描述系统中对象的类型和它们之间的关系。类图中的类结构和内容将被用来设计系统元素,例如:类、包或者对象。类图描述了在设计系统时的三种不同的方面,即概要设计、详细设计以及实现的过程。当类图设计好后,这些方面将明确,这也将巩固系统的设计。

        类图、物理数据模型以及系统整体模块图,在我看来对于现今快速应用程序的开发中是最重要的几个图。类图中,类之间的关系包括:关联、继承、实现、依赖、聚合以及组合,下面显示了类图中这些关系的UML标记法:

notation图3 类关系UML标记法

3.23 什么是包图(Package Diagram)?

        包图用来描述包和它们中的元素是如何组织的。当包图用来表示类元素时,包图将提供一个可见的命名空间。在我的设计中,我使用包图组织系统不同模块的类。

3.24 什么是顺序图(Sequence Diagram)?

        顺序图使用一种可见的方法描述系统逻辑的流程,它可以以文档的形式验证你的逻辑的正确性,顺序图既可以用来设计也可以用来分析。对于动态建模来说,顺序图是最重要的UML图,它将以识别系统行为为重点。

3.25 什么是两层架构(two-tier architecture)?

        两层架构通常指的是客户/服务器架构,对于现今来说,两层架构指的是客户端上的UI(或者ASP.NET和其它网页)和服务器上的数据库。实际的应用程序逻辑既可以在客户端上也运行也可在服务器上运行。所以在这种情况下客户端将直接访问数据库。两层架构也可以是无接口处理引擎,它为远程或者本地系统提供解决方案。总之,对于上述任何一种两层架构的使用方式,它们都没有三层架构模型那么普遍。两层架构的特点是它们很简单,但是简单却牺牲了扩展性。更普遍的三层架构则引入了应用程序逻辑中间层。下图显示了两层架构:

2-Tier 图4 两层架构

3.26 什么是三层架构(three-tier architecture)?

        三层架构是为了解决两层架构扩展性低的缺点而建立的,它被已经现今的系统设计者广泛的采纳,无论是在网页系统还是应用程序中。

        三层架构是客户端-服务器架构,它包括了UI、业务逻辑处理以及数据存储以及数据访问部分,这些部分将按照独立模块的方式进行开发和维护。另外,我们经常听到的N层架构其实通常是指三层架构。下面是三层架构的架构图:

3-Tier图5 三层架构图

        三层架构通常包含以下三层:

        1.展现层或Web Server:UI,显示数据或者接收用户的输入;

        2.应用程序逻辑、逻辑层、事务层或者Application Server:数据验证、数据库插入前的检查以及其它业务和应用程序操作;

        3.数据层或者Database Server:简单的读写数据库或者其它存储、连接、命令以及存储过程。

3.27 什么是MVC架构?

        Model-View-Controller (MVC)架构将程序的领域模型和其数据表示以及建立在用户输入基础上的动作进行了分离。MVC经常被错误的使用,因为很多技术(例如:java和asp.net)按照自己的方式定义MVC,这使得它很难被理解。通常,controller在不同的上下文中被理解为不同的事物。下面的定义是我从Asp.net中找到的可能的MVC版本:

mvc图6 MVC架构

        1.Model:类型为DataSet的数据集(有时是业务对象、对象集合或者XML)是最常用的模型;

        2.View:ASPX和ASCX文件通常处理View的职责,对象了展现层的数据显示和用户输入接收;

        3.Controllers:事件处理或者控制在code-behind类中。

        在复杂的N层架构的分布式系统中MVC的关键作用是把系统的展现层组织了起来。

3.28 什么是SOA(Service-Oriented Architecture)?

        SOA本质上是一个服务的集合。这些服务间互相通信,服务间通信可以是简单的数据传送,或者两个或者多个服务一起协调一些活动。

        .NET技术中,SOA是通过Web Services实现的。下面的图显示了SOA的架构:

SOA 图7 SOA架构

       SOA可以理解为连接多个系统,以这种方式提供服务。它在IT界中将会占有很重要的地位。

       根据上面的SOA架构图,我们可以看出SOA是怎么被用来向市民提供集中式服务的。市民每个人都拥有一张ID卡(唯一的,卡里包含市民的个人信息)。每个服务中心,例如购物中心、医院以及车站和工厂都安装了电脑系统,通过这些系统都连接到了城市中央服务器,这些服务器向城市居民提供了服务。例如:当一个客户进入购物中心时,购物中心电脑系统将与中央服务器通信获取客户的信息,完成身份确认后系统将会欢迎客户,客户就可以选择择自己的购买物了,当客户购买完商品后,在他离开时,将通过电脑系统的结算流程进行购物结算,这些过程都是购物中心电脑系统管理的。支付将根据客户的ID卡上获取的信息而被自动处理。

        区域系统将与城市中心系统通信,而城市系统将与全国系统进行通信。

3.29 什么是数据访问层(Data Access Layer)?

        数据访问层(DAL)是任何N层系统的关键部分,它包含了一些了与数据库或者其它存储设备交互的代码。这些功能通常是指CRUD(Create、Retrieve、Update和Delete)。

        数据访问层需要做的尽量通用、简单、快捷以及高效,它不应该包含复杂的业务逻辑。

        我在以前做的项目中看到了很多很长、复杂的存储过程(store procedures或SP),它们使用了不同的case语句只为了做简单的选择操作,它们包含了大量的业务逻辑。如果SP变的很长很复杂的话,这说明你正在将业务逻辑混杂在数据访问层中。

总结

        本部分到此就算是结束了,总而言之,良好的面向对象编程基础对于设计良好的系统是非常关键的,一个良好设计的系统是成功的关键。当我们讨论系统设计的时候,正确地处理OOP的概念真的很重要。希望大家在今后的学习中重视基础的掌握。

        本系列的文章分为三个部分,在写的过程中肯定有遗漏,因为OOP的概念过于复杂,希望大家能够理解,有什么疏漏的地方请大家提出来,欢迎多多交流,谢谢!

posted on 2010-05-02 14:33  building7  阅读(859)  评论(0编辑  收藏  举报

导航