对设计模式不是很熟悉,现在碰到一个比较棘手的问题,不知道应该如何设计,请大家帮忙看一看。现在有两种用于快速处理订单的业务A、业务B,分别用于处理订单A和订单B,他们的逻辑都是相似的,基本逻辑就是:(1)初始化业务的各项基础数据
(2)接受一个订单,放入到待处理订单缓冲
(3)从待处理缓冲读取一个订单并开始处理,并将处理完的订单放入到已处理缓冲
(4)定期检测已处理缓存,当已处理缓冲区达到一定数量之后就同步写入数据库上述逻辑的设计是考虑到订单的数量非常庞大(高峰时段每秒需要接受10~100个订单),并且订单发出后用户无需等待处理状态,所有订单在第二步都是可以成功处理的。每个订单如果即时写入数据库,会造成数据库无法负担。因此业务A和业务B都包含下列线程:
(1)主线程:用于接受客户端请求
(2)初始线程:完成系统初始化
(3)处理线程:处理队列
(4)同步更新线程:更新到数据库系统采用.Net Remoting技术进行部署,为了减少并发冲突,我的想法是:主线程使用实例变量形式,而待处理缓冲和已处理缓冲都采用静态变量形式,响应的初始线程、处理线程和同步更新线程都均采用静态变量形式。因此我打算写一个基础类,业务A和业务B都该基础类进行继承,基类的代码可以简单概况为:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Threading;
using System.Text;namespace MyProgram
{
    public class OrderBaseObj : MarshalByRefObject
    {
        // 待处理订单列表
        protected static List<OrderItem> lstUnHandle = new List<OrderItem>();        // 已处理订单列表
        protected static List<OrderItem> lstHandle = new List<OrderItem>();        // 初始化是否完成标记
        protected static bool blnInitFinished = false;        // 待执行的数据库事务表
        protected static List<string> lstUpdateCommand = new List<string>();        // 初始化线程
        protected static Thread threadInit = null;        // 处理线程
        protected static Thread threadHandle = null;        // 数据库同步线程
        protected static Thread threadDB = null;        static OrderBaseObj()
        {
            ThreadStart tst = new ThreadStart(ThreadInit_Start);
            threadInit = new Thread(tst);
            threadInit.Priority = ThreadPriority.BelowNormal;
            threadInit.Start();            tst = new ThreadStart(ThreadHandle_Start);
            threadHandle = new Thread(tst);
            threadHandle.Priority = ThreadPriority.Lowest;
            threadHandle.Start();            tst = new ThreadStart(ThreadDB_Start);
            threadDB = new Thread(tst);
            threadDB.Priority = ThreadPriority.Lowest;
            threadDB.Start();
        }        /// <summary>
        /// 添加一个PV到待处理区
        /// </summary>
        public void AddPV(OrderItem order)
        {
            lstUnHandle.Add(order);
        }        // 初始线程启动方法
        private static void ThreadInit_Start()
        {
            Init();
            blnInitFinished = true;
        }        // 初始化抽象方法
        protected static abstract bool Init();        // 处理线程启动方法
        private static void ThreadHandle_Start()
        {
            while (true)
            {
                OrderItem order=lstUnHandle[0];
                lstUnHandle.RemoveAt(0);                HandleOrder(order);
                lstHandle.Add(order);
                
                if(lstHandle.Count>100)
                {
                    string strCommmand=HandleUpdateCommmand();
                    lstUpdateTrans.Add(strCommand);
                    lstHandle.Clear();
                }
            }
        }        // 订单处理的抽象方法,每个子类必须实现该方法
        protected abstract static void HandleOrder(OrderItem order);        // 返回处理数据库同步更新命令
        protected abstract static string HandleUpdateCommmand();        // 同步线程启动方法
        private static void ThreadDB_Start()
        {
            while (true)
            {
                if (lstUpdateTrans.Count > 0)
                {
                    string strCommand=lstUpdateTrans[0];
                    lstUpdateTrans.RemoveAt(0);                    DBObj db=new DBObj();
                    db.Execute(strCommand);
                    db.CloseConn();
                }                Thread.Sleep(new TimeSpan(0, 0, 2));
            }
        }
    }
}上面代码的问题就是:静态方法不能描述为抽象方法,如果不采用基类的方式,直接在业务A或者业务B里面实现,上面的思路是没有问题的(不采用抽象方法),当然很多代码会重复,如果需要增加订单类型,就要增加业务类,维护起来不方便。如果一定要实现一个基类,那么这么基类应该怎么写呢?

解决方案 »

  1.   

    To:Zhiang75谢谢您的回答,如果通过基类不能解决,应该用什么方式来解决呢?关于数据库的性能,因为本身服务器还有很多其他处理,通过汇总事务,然后批次写入有助于减低数据库开销。
      

  2.   

    假设为了提高系统的运行效率..我们采用每步负责制,假设我们使用文件系统作缓冲,步骤就有客户录入定单->IIS保存订单数据到TEM目录->预处理线程将数据文件批次转换为内存数据>将内存数据批次存入数据库
                |                 |              |
                基类               基类             基类这就要3个基类了
      

  3.   

    呵呵,你的核心问题不是在设计模式上面,核心问题是在线程上面,设计模式只是想要封装变化,帮助你在添加新的订单类型的时候很方便。首先在效率上面,你可以采用自己做一个线程池,放入更多的工作线程在里面,将订单任务分解到工作线程里面去处理,以前我做过的一个系统,效率要求可以说是你描述的数量级上要高出来一级的,采用这种方式都可以轻松搞定(当然对服务器和.net framework要有一定的调整)。在数据库上面,看是SQL Server还是Oracle了,两种调优方式不太一样,SQLServer每秒钟单表访问在800次以上问题不大,关键看你是怎么调优的,Oracle也不会比SqlServer弱。你的效率问题,首先是要找到瓶颈,然后才能去解决。
    然后设计模式上你去仔细看看模板方法那一个模式吧,正好可以解决你的这个问题。
      

  4.   

    To:Realsnow:谢谢你的回答,实质上采用我上面的思路,性能基本上已经不成问题了,如果不采用基类,直接将某个业务的代码全部写在一起,已经可以满足我的要求,并且也不需要线程池,经过压力测试,即便采用SQL Server,在峰值每秒处理1000甚至10000个订单的情况下仍能运行良好。现在最大的问题就是,如果需要考虑多个业务,并且逻辑基本一致的情况下,我希望简化编码,将通用的东西抽象出来成为一个基类,不同的业务根据不同的情况进行适当重写部分方法即可。那个这么基类如何抽象?
      

  5.   

    To:zhiang75 我不是很理解你的那个思路,你可能想通过文件系统进行中转,我现在采用的内存而已,减少磁盘IO的吞吐。应该本质上还是一致的
      

  6.   

    呵呵,你的第二个问题我也回答了,好好的研究模板方法这个设计模式,正好解决你的问题。或者查template method,你可以看到很多这方面的。具体的我就不讲了,在这里说太费劲
      

  7.   

    http://www.cnblogs.com/webabcd/archive/2007/03/13/673658.html
    LOOK这个对你的开发应该有帮助..
    还有OO提倡瘦对象,即单一职能..看了LZ的思路是有OO的思想的,我的意见就是把这个胖对象拆成几个瘦对象..
      

  8.   

    谢谢Zhiang75,我自己再研究一下,看如果拆分对象是否对解决我的问题有帮助。现在越来越觉得OO的思想不那么简单啊……虽然做了多年的开发。
      

  9.   

    我不太明白的地方就是:既然你用到抽象方法,就意味着继承类需要重新实现这个方法,就意味着不同的继承类应该有不同的处理方式,但却为什么要静态呢?静态就是在运行过程中只有一个副本,而事实上你不同的继承类就有不同的实现方法,根本不应该用静态啊?如果是不同的继承类中的你所提到的抽象方法需要用静态的话,建议使用Bridge的方式来实现你的设计,或者用Abstract Factory。
      

  10.   

    类似 
    // 初始化抽象方法
    protected static abstract bool Init();
    需要修改一下:
    protected abstract bool Init();
    不要用静态
      

  11.   

    LZ,我最近在学习PetShop4.0,我感觉这个里面的抽象工厂模式和消息队列及缓存技术能解决你的问题.
      

  12.   

    Abstract Factory模式昨天也好好研究了一下,可能对设计模式理解较浅吧,现在还不知道应该如何抽象里面的类出来。呵呵,暂时问题还没有解决,还在努力寻找解决方案中。
      

  13.   

    Gof提倡的是合成复用原则:即少用继承,多用合成.所以应该把各个大的功能拆分成小的功能类,每个类要完成它该干的事,并且要把它该干的事干好.不该它干的事它不要管.
    你想给业务A和业务B写一个基类,这不重要,我想.当然你可以这么做.
    由于涉及订单处理这样的业务逻辑,可以考虑采用workflow,不过似乎目前不微软的workfolw不支持2003,那你只能用开源的了.主程序将订单(订单要求可序列化)传给workflow(宿主在windows service),由workflow处理,处理后的订单直接插入微软的消息队列(参看.net petshop 4.0),这样你不必担心订单的丢失,你的方法似乎有丢失订单的可能性.再由消息队列的Windows service将处理后的订单同步(或异步)插入数据库.
    至于你说的线程A线程B我想都是针对业务逻辑的,没必要和数据操作放在一起来处理,采用分层的结构比较好.以上仅供参考.
      

  14.   

    To:mythad 谢谢你的解答,不过我想这样是不是越搞越复杂了吧,其实如果是单个业务A或者业务B,如果不需要考虑以后扩展业务类型容易的问题,现在我认为已经解决了很好了。在整体部署方面,由于采用了.Net Remoting部署,客户端通过TCP通道连接到服务器中的服务程序,如果服务连接不上,那么则将订单暂时缓存在客户端的缓存中(因为客户端无需等待状态),当服务联通时再批量重新发送过去。在这种机制上,到目前位置,进行过的压力测试中,还没有试过丢失订单。在这个系统里面,订单处理过程并不复杂,涉及的逻辑也比较简单。当然,我现在没有拆分功能类,代码有点长,一个业务A的代码大概有2000多行。