十年磨一劍--從程序員到架構師

一个.net程序员,一个企业应用的开发者,喜欢系统架构,数据库,领域驱动,面向对象,表现层技术。关注重用的理论和实践。设计原则:简单,快速,适应变化能力强,表现层灵活多变...

博客园 首页 新随笔 联系 订阅 管理
  49 Posts :: 0 Stories :: 721 Comments :: 26 Trackbacks

公告

java,c#等语言出道以来﹐OO着实风光了一把﹐一时间"祖国江山一片O"

 

不得不说﹐OO思想确实较之之前的软件设计方法给人耳目一新的感觉﹐然而要说放之四海而皆O﹐恐怕就值得商榷了。至少在以处理数据为主的业务系统(Business ApplicationOriented-Data Application)中﹐OO并不能代替数据库(这里指关系数据库)完成业务系统中最核心的业务逻辑定义和存储。

 

OO语言﹐较之过程化vbscript的最多只能封装一些函数﹐而在抽象﹐重用﹐变化等方面的无可奈何﹐OO以其解决这些问题的简洁和完美赢得了系统设计师的青睐﹐也就是在那时候开始﹐就忘了业务系统中另一个与过程化语言起完全不同作用的数据库。

 

代之而起的数据库已死”OO与数据库存在天然阻抗对象必将代替数据库等言论漫天飞舞﹐一时间大有不置数据库于死地誓不罢休的感觉。

 

可笑的是﹐虽然有着这么道貌岸然的口号﹐但是OO们依然离不开数据库﹐为了掩饰其尴尬处境﹐只好再弄个O/R Mapping﹐并宣称﹕系统中的OO对象﹐可以通过ORM转成关系﹐然而再存到数据库﹐数据库在我的系统中只是一种持久化方式﹐让我的OO可以再次复活﹐除此之外﹐别无他意云云。

 

再看看剥离了数据库而独立存在的OO们是如何来表示业务逻辑的吧?

 

首先要进行对象设计﹐提取领域模型(各种叫法﹐随便)﹐虽然OO有其显著特征和丰富手段来进行封装﹐抽象以应对变化。但是对于OO中对象之间的关系却毫无办法﹐只能简单的通过属性来描述。没有标准的结果就是自由设计﹐并自我安慰﹕这就是OO﹐因为OO是模拟现实的呀﹐你看我要加一个属性时﹐多方便﹐几行代码搞定。看得出来﹐OO之间的关系是一种网状关系的﹐以数据结构的朮语来说﹐就是图(较之数据库关系模型的集合理论﹐图要复杂不知多少)

 

然而自由就意味着要付出代价﹐因为OO中的对象是需要持久的﹐除非CPU能够直接访问硬盘﹐或者内存在掉电之后数据可以继续存在。OO还是不得不借助于数据库帮其持久(不要提对象数据库﹐除非有新理论出来﹐对象数据库应该是一种网状数据库﹐事实已证明﹐关系数据库在描述的简洁性﹐查询的方便性﹐性能的优越性等方面都优于网状数据库)﹐因此OO也必须转成关系模型存储到数据库之中﹐各种O/R Mapping也随之而来。

 

何苦呢?本来就是同一个东西﹐为什么偏要转来转去﹐多麻烦。

 

举个最常见的例子﹕订单系统可能有这样两个对象﹕订单和客户﹐为了表示下单的人是谁﹐就在订单对象里加了一个属性﹕下单者。而某些时候可能又需要知道哪位客户下了哪些订单﹐因此又在客户类里加上了订单列表属性﹐表示这个客户下过的订单。

 

明眼人已经看出﹐OO表示对象之间关系的繁琐。同一个关系﹐需要两次或者多次描述。

 

而数据库的关系模型则简单得多﹕

实体﹕订单﹐客户

关系﹕下单(订单号﹐客户ID)

要知道下单者﹐通过下单关系﹐要知道客户的订单﹐也通过下单关系。

勿庸置疑﹐关系模型在描述实体(或对象)之间关系的简洁和有效性。

 

这就是伟大的数据库的关系模型﹐比之对象的自由的网状模型﹐其优点自不必说。

 

如何解决关系与对象的不匹配了﹐其实很简单﹐以关系模型理论来指导对象设计。

如上述例子需要设计三个对象(两个实体﹐一个关系)﹕订单和客户﹐下单对象(表示订单和客户的关系)﹐一个下单对象有如下属性(下单者和订单两个属性﹐其属性类型自然是两个对象了)

    /// <summary>

    /// 产品

    /// </summary>

    class Product

    {

        public string name;        //产品名称

        public decimal price;      //单价

    }

 

    /// <summary>

    /// 订单

    /// </summary>

    class Order

    {

        public string no;          //订单号

               

        public DateTime date;      //订单日期

 

        public Product product;    //产品

 

        public int quantity;       //数量

 

        public decimal amount{get{return product.price * quantity;}}     //金额

    }

 

    /// <summary>

    /// 客户

    /// </summary>

    class Customer

    {

        public string name;         //姓名

 

        public string address;      //地址

 

        public string email;        //Email

    }

 

    /// <summary>

    /// 下单关系

    /// </summary>

    class OrderCustomerRelation

    {

        Order order;                //订单

        Customer customer;          //下单者

    }

 

    /// <summary>

    /// 订单关系集合

    /// </summary>

    class OrderCustomerRelList

    {

        public static OrderCustomerRelList Instance

        {

            get { return new OrderCustomerRelList(); }     //完成实例抓取

        }

        public List<OrderCustomerRelation> Lists;

    }

通过下单这个对象来描述订单的客户。为了方便﹐你可以在订单类中增加一个获取客户方法﹐这个方法通过下单对象集合来实现。而你在客户类中增加的订单列表属性﹐也是通过查询下单对象集合来完成。

    /// <summary>

    /// 订单

    /// </summary>

    class Order

    {

        public string no;          //订单号

 

        public DateTime date;      //订单日期

 

        public Product product;    //产品

 

        public int quantity;       //数量

 

        public decimal amount { get { return product.price * quantity; } }     //金额

 

        public Customer customer

        {

            get

            {

                OrderCustomerRelList list = OrderCustomerRelList.Instance;

                foreach (OrderCustomerRelation rel in list.Lists)

                {

                    if (rel.order.Equals(this))

                        return customer;

                }

                return null;

 

                //更酷的查询表达式实现

                //return list.Lists.First(rel => rel.order.Equals(this)).customer;

            }

        }

    }

 

    /// <summary>

    /// 客户

    /// </summary>

    class Customer

    {

        public string name;         //姓名

 

        public string address;      //地址

 

        public string email;        //Email

 

        /// <summary>

        /// 现实一些﹐应该设计一个类封装List<Order>﹐以便其AddRemove方法可以实现Relation的增和删

        /// 当然可以根据实际需要﹐决定在OrderSet_customer中完成下单逻辑﹐就没必要在这个类的orders中完成下单逻辑

        /// </summary>

        public List<Order> orders

        {

            get

            {

                List<Order> ret = new List<Order>();

                OrderCustomerRelList list = OrderCustomerRelList.Instance;

                foreach (OrderCustomerRelation rel in list.Lists)

                {

                    if (rel.customer.Equals(this))

                        ret.Add(rel.order);

                }

                return ret;

 

                //更酷的linq实现

                //var tmp = from rel in list.Lists where rel.customer.Equals(this) select rel.order;

                //return tmp.ToList<Order>();

            }

        }

 

    }

 

也许这样设计你认为Client需要操作关系很不自然﹐其实没关系﹐做一层封装即可﹕让订单类的客户属性可以set,set中再完成关系的建立。

 

    /// <summary>

    /// 订单

    /// </summary>

    class Order

    {

        public string no;          //订单号

 

        public DateTime date;      //订单日期

 

        public Product product;    //产品

 

        public int quantity;       //数量

 

        public decimal amount { get { return product.price * quantity; } }     //金额

 

        public Customer customer

        {

            get

            {

                OrderCustomerRelList list = OrderCustomerRelList.Instance;

                foreach (OrderCustomerRelation rel in list.Lists)

                {

                    if (rel.order.Equals(this))

                        return customer;

                }

                return null;

 

                //更酷的查询表达式实现

                //return list.Lists.First(rel => rel.order.Equals(this)).customer;

            }

            set

            {

                OrderCustomerRelList list = OrderCustomerRelList.Instance;

                var relation = list.Lists.First(rel => rel.order.Equals(this));

                if (relation != null)

                    relation.customer = value;

                else

                {

                    relation = new OrderCustomerRelation();

                    relation.customer = value;

                    relation.order = this;

                    list.Lists.Add(relation);

                }

            }

        }

    }

 

再进一步﹐你可以设计一个O/R Mapping框架﹐当然也可以选择现有ORM方案﹐来实现对象与实体﹐关系与关系的完全对应﹐最后完全”OO”

 

随着.net 3.5 sp1的发布﹐这个框架MS已帮你实现了﹐这就是ado.net entity framework(注﹕不是广告﹐我也不是MS的托﹕)

 

简单谈一下我对entity framework的看法﹕虽然第一眼看去﹐似乎也是个O/R Mapping﹐但是与以往ORM不同的是﹐它提出了一种理论﹐以关系模型来设计对象﹐然后再进行Mapping﹐这比只有工具﹐而无思想的其它ORM们更进了一步。至于其e sql,linq to entity更是让操作起这个ORM来随心所欲~

 

本是同根生﹐相煎何太急OO与数据库就像人的五官一样﹐各司其职﹐各负其责﹐OO负责设计系统架构﹐业务流程﹐实现抽象﹐封装变化。而数据库则负责业务逻辑的表示﹐存储和查询。通过关系模型﹐架起OO与数据库的勾通的有效桥梁。

 

和为贵﹗

 

最后祝园子里的TX们中秋快乐﹐家好月园﹕)

 

posted on 2008-09-11 11:03 Kevin Zou 阅读(...) 评论(...) 编辑 收藏