SmartPublisher设计之旅 — 让理想在仇恨中茁壮成长

一句台词引发的思考 updated 1.15 21:59

昨天晚上看了一部电视剧,其中一句台词说得不错:"其实很多的事情非常复杂,包括爱情,有时候甚至可以在仇恨的尸体上茁壮成长"。爱情是微妙的,它是所有感情家族里最年轻、最可爱、最单纯、最善良、最柔弱、最自私的一员,所以它害怕受到、也容易受到伤害。这正是我们常说的"爱之深,恨之切"。

有一个真实的故事。话说有一出身贫困地区的初中生(小A),他性格比较内向,成绩也很差。有一次,他跟一名同班同学(小B)发生口角。在吵架中,小B取笑小A,说:“象你这样的笨猪如果能考上大学,我认你做老子”。或许有些人听到这句不经意的话会一笑了之,然而对小A来说确实是一种侮辱,自尊心受到极大伤害。从那以后,小A开始痛恨小B,下定决心一定要考上大学,开始非常刻苦学习。多少年来,小B的“侮辱”成了小A不断进步的动力。工夫不负有心人,小A如愿以偿的考上了大学。参加工作以后,小A一次回家探亲,偶然遇见小B,可他当时心里已经不再是痛恨,取而代之是无限的感激。

在2007年的中国互联网界里,最引人瞩目的应该是阿里巴巴,而在阿里巴巴集团上下,最引人瞩目的应该是素有"网络狂人"之称的马云。从父亲拳脚下长大的差生到大学英语教师,从不懂电脑到全球著名的网络公司的掌门人,马云这样不断创造出奇迹。昔日的笑柄现已成了马云吹牛的资本。其实,从马云在媒体里表露出来的这种狂妄的语言中,我们不难发现,在马云身上有一种对那些看不起他、鄙视他的人的“仇恨”。

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

mayun.jpg

或许人就必须在不断遭受挫折、不断遭受打击的过程中慢慢的走向成熟。黑人领袖马丁·路德金说过;“这个世界上,没有人能够使你倒下,如果你自己的信念还站立的话。”

IT? 还是挨踢?

IT人作为计算机技术的开拓者、推动者、传播者,早已成为我们的代名词。然后,当我们在拥有知识的同时,却常常自嘲为"挨踢人"。挨风云变幻的技术之所“踢”,挨用户的不满之所“踢”,挨旁人的冷言冷语之所“踢”。可不管怎么"痛",我们还是能感受到浩瀚的知识带给我的快乐和满足。所以,我们仍然毫无怨言的、顽强的站立着,并且将永远的走下去。

在软件开发过程中,我们常常遇到这样的情况:开发工作已经进行到了后期,这时客户打来一个电话,推翻了之前与客户再三讨论而确定下来的需求,但又无法拒绝客户的要求,这时又得重新跟客户进行新一轮的需求讨论,甚至是无休止的讨论,最后导致必须重新设计现有的架构。我相信,每一个开发人员都饱受过需求变化带来的痛苦。《解析极限编程拥抱变化》写道:“任何情况下,变化是绝对的,不变是相对的,我们不要抱怨变化的发生,重要的是要有应付变化的能力”。

说了这么多费话,现在言归正传。在《SmartPublisher设计之旅 - 优秀的设计才是让软件永葆青春的秘诀》中,我们已经对SmartPublisher数据访问层进行了设计,下面我们来探讨的业务逻辑层的设计。

业务逻辑层(Business Logic Layer)设计

业务逻辑层:在三层架构中,业务逻辑层是所有业务逻辑的集中地,是整个系统的核心。它关注业务规则的制定,并为表示层提供服务。业务逻辑层主要负责数据的合法性检查,如企业注册时录入的帐号是否已被注册;还有业务操作组合处理,比如在某一个功能中需要对多个数据表进行分步操作(如订单保存Master和Detail),但是这些步骤是一个完整的业务逻辑。所以业务逻辑层设计应该按照功能需求进行设计,与业务紧密联系,所以在复杂的系统的中有时需要邀请业务专家参与设计。为了保证业务逻辑层的可扩展性,我将定义业务接口(IBLL)和具体业务类(BLL),并由具体业务类与数据访问层的接口集通讯。

从《SmartPublisher设计之旅 - 软件开发之前先做个梦》的需求分析中可以看出,SmartPublisher的功能主要包括两个层面:一是面向Web的应用;二是面向Windows Service引擎的应用。

首先,我们考虑Web应用的功能。

1、对企业会员需要实现的功能有:
·企业注册基本信息;
·企业会员登陆;
·企业修改基本信息;
·企业选择站点,发布基本信息;
·企业会员修改密码;
·管理员审核企业会员;
·管理员禁用/启用企业会员帐号;
·管理员删除企业会员基本信息;
·按照企业ID、企业会员帐号、企业会员名称、企业行业分类、是否会员、是否禁用等条件查询企业会员基本信息;
根据以上功能定义IEnterpriseBLL

None.gif using  System;
None.gif
using  System.Text;
None.gif
using  System.Data;
None.gif
using  PublisherLib.DataAccessLayer;
None.gif
None.gif
namespace  PublisherLib.BusinessLogicLayer
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
public interface IEnterpriseBLL
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
bool RegisterEnterprise(Enterprise model);
InBlock.gif        
bool Login(string enterpriseCode, string enterprisePassword);
InBlock.gif        
bool UpdateEnterprise(Enterprise model);
InBlock.gif        
bool UpdatePassword(string enterpriseID, string newEnterprisePassword);
InBlock.gif
InBlock.gif        
bool VerifyEnterprise(string enterpriseID, bool ismember);
InBlock.gif        
bool LockEnterprise(string enterpriseID, bool islock);
InBlock.gif        
bool DeleteEnterprise(string enterpriseID);
InBlock.gif        Enterprise GetEnterpriseByID(
string enterpriseID);
InBlock.gif        DataSet QueryEnterpriseList(
string strCondition);
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

2、对产品信息需要实现的功能有:
·企业会员录入产品信息;
·企业会员获取所有产品信息;
·企业会员修改产品信息;
·企业会员删除产品信息;
·企业会员选择站点,发布产品信息;
·按照条件查询产品信息;
根据以上功能定义IProductBLL

None.gif using  System;
None.gif
using  System.Text;
None.gif
using  System.Data;
None.gif
using  PublisherLib.DataAccessLayer;
None.gif
None.gif
namespace  PublisherLib.BusinessLogicLayer
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
public interface IProductBLL
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
bool AddProduct(Product model);
InBlock.gif        
bool UpdateProduct(Product model);
InBlock.gif        
bool DelelteProduct(string productID);
InBlock.gif        
InBlock.gif        Product GetProduct(
string productIDid);
InBlock.gif        DataSet GetProductsByEnterprise(
string enterpriseID);
InBlock.gif        DataSet GetProductList(
string strCondition);
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}


大家仔细看IEnterpriseBLL和IProductBLL方法定义,我在这里并没有定义发布企业基本信息和发布产品信息两个方法。因为不关是企业基本信息,还是产品信息,其发布过程都是一样的,只是信息内容不一样,发布之后写入T_RouterData表(详见《SmartPublisher设计之旅 — 让梦想成为理想》)。所以我抽象出一个信息发布接口,当然还考虑其他原因,请看后叙。

None.gif using  System;
None.gif
None.gif
namespace  PublisherLib.BusinessLogicLayer
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
public interface IPublishData
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
void Publish(string dataID, string[] aryWebSite);
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

接下来,定义定义EnterpriseBLL,并继承IEnterprise和IPublishData
ContractedBlock.gif ExpandedBlockStart.gif EnterpriseBLL
None.gifusing System;
None.gif
using System.Text;
None.gif
using System.Data;
None.gif
using PublisherLib.DataAccessLayer;
None.gif
None.gif
namespace PublisherLib.BusinessLogicLayer
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
public class EnterpriseBLL:IEnterpriseBLL,IPublishData
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
private static readonly ITableOperator<Enterprise> dal = DataFactory.CreateEnterprise();
InBlock.gif  
ContractedSubBlock.gifExpandedSubBlockStart.gif        
IEnterpriseBLL 成员#region IEnterpriseBLL 成员
InBlock.gif
InBlock.gif        
public bool RegisterEnterprise(Enterprise model)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return dal.Add(model);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public bool Login(string enterpriseCode, string enterprisePassword)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            DataSet ds 
= dal.GetList("Code='" + enterpriseCode+"' AND password='"+enterprisePassword+"'");
InBlock.gif            
if (ds == null || ds.Tables.Count == 0 || ds.Tables[0].Rows.Count == 0return false;
InBlock.gif
InBlock.gif            
return true;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public bool UpdateEnterprise(Enterprise model)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return dal.Update(model);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public bool UpdatePassword(string enterpriseID, string newEnterprisePassword)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            Enterprise model 
= dal.GetModel(enterpriseID);
InBlock.gif            model.Password 
= newEnterprisePassword;
InBlock.gif            
return dal.Update(model);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public bool VerifyEnterprise(string enterpriseID, bool ismember)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            Enterprise model 
= dal.GetModel(enterpriseID);
InBlock.gif            model.IsMember 
= Convert.ToByte(ismember);
InBlock.gif            
return dal.Update(model);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public bool LockEnterprise(string enterpriseID, bool islock)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            Enterprise model 
= dal.GetModel(enterpriseID);
InBlock.gif            model.IsLock 
= Convert.ToByte(islock);
InBlock.gif            
return dal.Update(model);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public bool DeleteEnterprise(string enterpriseID)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return dal.Delete(enterpriseID);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public Enterprise GetEnterpriseByID(string enterpriseID)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return dal.GetModel(enterpriseID);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public DataSet QueryEnterpriseList(string strCondition)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return dal.GetList(strCondition);
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion

InBlock.gif
ContractedSubBlock.gifExpandedSubBlockStart.gif        
IPublishData 成员#region IPublishData 成员
InBlock.gif
InBlock.gif        
public void Publish(string dataID, string[] aryWebSite)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            ITableOperator
<RouterData> dal = DataFactory.CreateRouterData();
InBlock.gif            
foreach (string websiteid in aryWebSite)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                RouterData model 
= new RouterData();
InBlock.gif                model.DataID 
= dataID;
InBlock.gif                model.DataType 
= "ENTERPRISE";
InBlock.gif                model.RouterID 
= websiteid;
InBlock.gif                model.RouterType 
= "WEBSITE";
InBlock.gif
InBlock.gif                dal.Add(model);
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

同理,定义定义ProductBLL,并继承IProduct和IPublishData,代码略。

3、对商务站点需要实现的功能有:
·新增创建站点;
·修改站点信息;
·禁用站点;
·删除站点信息;
·获取站点信息;
·按照条件查询站点信息;
根据以上功能定义IWebSiteBLL和WebSiteBLL,代码略。

4、对发布日志需要实现的功能有:
·新增日志;
·按照条件查询日志;
·按照被发布信息(企业/产品)统计成功条数和成功率;
·按照企业会员统计发布信息成功条数和成功率;
根据以上功能定义IPublishLogBLL和PublishLogBLL,代码略。

接下来,我们考虑发布引擎的功能。在讨论之前,请先看看SmartPublisher的网络图。就目前需求来说,比较简单,主要做两件事情:发布信息;记录发布日志。引擎的性能直接决定了SmartPublisher软件的性能。所以在这里,我采用MSMQ,主要原因如下:
1) 会员在发布企业/产品信息的同时,把信息发送到MessgeQ中,这也是为什么需要定义IPublishData的原因。
2) 发布引擎从MessgeQ接受消息比从数据库查询效率更高,特别是数据库的数据量大的时候更明显。
3) 发布引擎采用MSMQ技术以后,减少了对BLL的依赖,即在运行时只需监控MessgeQ即可。

既然采用MSMQ技术,IPublishData分别在EnterpriseBLL和ProductBLL中所实现的Publish方法明显有问题。这时,我们最直接的解决办法是在EnterpriseBLL和ProductBLL的Publish方法在写入数据库的同时,把信息发送到MessgeQ。从合理设计的角度来说,这种方法非常不可取,因为这样一来我们就已经把消息发送的功能固化在EnterpriseBLL和ProductBLL的Publish方法中,无法撤消。所以在这里我们可以通过装饰模式(Decorator)为Publish方法附加发送信息的功能。消息发送接口如下:

None.gif using  System;
None.gif
None.gif
namespace  PublisherLib.BusinessLogicLayer
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
public interface ISendMessage
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
void Send(string dataID, string[] aryWebSiteID);
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

然后定义SendEnterpriseMessageBLL和SendProductMessagegBLL进行发送消息。

ContractedBlock.gif ExpandedBlockStart.gif SendEnterpriseMessageBLL
None.gifusing System;
None.gif
using System.Collections;
None.gif
using System.Messaging;
None.gif
using PublisherLib.DataAccessLayer;
None.gif
None.gif
namespace PublisherLib.BusinessLogicLayer
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
public class SendEnterpriseMessageBLL:EnterpriseBLL,ISendMessage
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
private string _QueuePath;
InBlock.gif        
public SendEnterpriseMessageBLL(string queuePath)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
this._QueuePath = queuePath;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ContractedSubBlock.gifExpandedSubBlockStart.gif        
ISendMessage 成员#region ISendMessage 成员
InBlock.gif
InBlock.gif        
public void Send(string dataID, string[] aryWebSiteID)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
//创建XML消息,包含发布信息和发布站点
InBlock.gif
            string dataXML = "";
InBlock.gif
InBlock.gif            MessageQueue messageQueue 
= new System.Messaging.MessageQueue(this._QueuePath);
InBlock.gif            
InBlock.gif            messageQueue.Send(dataXML);
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

ContractedBlock.gif ExpandedBlockStart.gif SendProductMessageBLL
None.gifusing System;
None.gif
using System.Collections;
None.gif
using System.Messaging;
None.gif
using PublisherLib.DataAccessLayer;
None.gif
None.gif
namespace PublisherLib.BusinessLogicLayer
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
public class SendProductMessageBLL:ProductBLL,ISendMessage
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
private string _QueuePath;
InBlock.gif        
public SendProductMessageBLL(string queuePath)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
this._QueuePath = queuePath;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ContractedSubBlock.gifExpandedSubBlockStart.gif        
ISendMessage 成员#region ISendMessage 成员
InBlock.gif
InBlock.gif        
public void Send(string dataID, string[] aryWebSiteID)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
//创建XML消息,包含发布信息和发布站点
InBlock.gif
            string dataXML = "";
InBlock.gif
InBlock.gif            MessageQueue messageQueue 
= new System.Messaging.MessageQueue(this._QueuePath);
InBlock.gif            messageQueue.Send(dataXML);
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

然后定义装饰类(DataDecorator),并继承IPublishData接口

ContractedBlock.gif ExpandedBlockStart.gif DataDecorator
None.gifusing System;
None.gif
None.gif
namespace PublisherLib.BusinessLogicLayer
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
public class DataDecorator:IPublishData
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
private IPublishData _PublishData;
InBlock.gif        
public IPublishData PublishData
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn _PublishData; }
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public DataDecorator(IPublishData publishdata)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
this._PublishData = publishdata;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ContractedSubBlock.gifExpandedSubBlockStart.gif        
IPublishData 成员#region IPublishData 成员
InBlock.gif
InBlock.gif        
public virtual void Publish(string dataID, string[] aryWebSite)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
this._PublishData.Publish(dataID, aryWebSite);
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

定义具体装饰类(DataMessageDecorator),继承(DataDecorator)

ContractedBlock.gif ExpandedBlockStart.gif DataMessageDecorator
None.gifusing System;
None.gif
None.gif
namespace PublisherLib.BusinessLogicLayer
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
public class DataMessageDecorator : DataDecorator
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
private ISendMessage _SendMessage;
InBlock.gif        
public ISendMessage SendMessage
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn _SendMessage; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ _SendMessage = value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif        
public DataMessageDecorator(IPublishData publishdata)
InBlock.gif            : 
base(publishdata)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockEnd.gif        }

InBlock.gif        
public override void Publish(string dataID, string[] aryWebSite)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            _SendMessage.Send(dataID, aryWebSite);
InBlock.gif            
base.Publish(dataID, aryWebSite);
InBlock.gif            
return;
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

发布引擎设计

SmartPublisher发布引擎以控制台程序或Windows Service方式运行。目前,SmartPublisher是将信息发布到商务站点上,考虑到以后有其他发布途径,我们可以定义一个发布路由(IRouter)

None.gif using  System;
None.gif
None.gif
namespace  PublisherEngine.Engine
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
public interface IRouter
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
string ID dot.gifget;set;}
ExpandedSubBlockStart.gifContractedSubBlock.gif        
string Address dot.gifget;set;}
ExpandedSubBlockStart.gifContractedSubBlock.gif        
string Parameters dot.gifget;set;}
InBlock.gif        
void PublishTo(Data data);
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

站点路由类(SiteRouter)继承IRouter,如果有其他如邮件群发则定义EmailRouter,也继承IRouter。

ContractedBlock.gif ExpandedBlockStart.gif SiteRouter
None.gifSiteRouter
None.gif
using System;
None.gif
None.gif
namespace PublisherEngine.Engine
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
public class SiteRouter:IRouter
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ContractedSubBlock.gifExpandedSubBlockStart.gif        IRouter 成员
IRouter 成员#region IRouter 成员
InBlock.gif
InBlock.gif        
public string ID
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
throw new Exception("The method or operation is not implemented.");
ExpandedSubBlockEnd.gif            }

InBlock.gif            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
throw new Exception("The method or operation is not implemented.");
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public string Address
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
throw new Exception("The method or operation is not implemented.");
ExpandedSubBlockEnd.gif            }

InBlock.gif            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
throw new Exception("The method or operation is not implemented.");
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public string Parameters
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
throw new Exception("The method or operation is not implemented.");
ExpandedSubBlockEnd.gif            }

InBlock.gif            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
throw new Exception("The method or operation is not implemented.");
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public void Publish(Data data)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
//发布信息,并且保存发布日志
InBlock.gif
            throw new Exception("The method or operation is not implemented.");
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

由于企业会员发布信息时需要根据行业多个同行业的站点,所以我们定义一个路由集合类(RouterList)。当MessageQ有消息,则通过遍历路由集合类调用IRouter的Publish方法进行发布,这正是迭代器模式(ITerator)的运用场景。Publish方法的参数Data为待发布信息。迭代器接口定义如下:

None.gif using  System;
None.gif
None.gif
namespace  PublisherEngine.Engine
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
public interface IRouterIterator
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
int index dot.gifset;get;}
InBlock.gif        
void Add(IRouter router);
InBlock.gif        
void Remove(IRouter router);
InBlock.gif        
void First();
InBlock.gif        
void Last();
InBlock.gif        
bool MovePrevous();
InBlock.gif        
bool MoveNext();
ExpandedSubBlockStart.gifContractedSubBlock.gif        IRouter Current 
dot.gifget;}
ExpandedSubBlockStart.gifContractedSubBlock.gif        
int Count dot.gifget;}
InBlock.gif        
void Clear();
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

路由集合类(RouterList)继承IRouterITerator。

ContractedBlock.gif ExpandedBlockStart.gif RouterList
None.gifusing System;
None.gif
None.gif
namespace PublisherEngine.Engine
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
public class RouterList : IRouterIterator
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ContractedSubBlock.gifExpandedSubBlockStart.gif        
IRouterIterator 成员#region IRouterIterator 成员
InBlock.gif
InBlock.gif        
public int index
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
throw new Exception("The method or operation is not implemented.");
ExpandedSubBlockEnd.gif            }

InBlock.gif            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
throw new Exception("The method or operation is not implemented.");
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public void Add(IRouter router)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
throw new Exception("The method or operation is not implemented.");
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public void Remove(IRouter router)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
throw new Exception("The method or operation is not implemented.");
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public void First()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
throw new Exception("The method or operation is not implemented.");
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public void Last()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
throw new Exception("The method or operation is not implemented.");
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public bool MovePrevous()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
throw new Exception("The method or operation is not implemented.");
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public bool MoveNext()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
throw new Exception("The method or operation is not implemented.");
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public IRouter Current
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifthrow new Exception("The method or operation is not implemented."); }
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public int Count
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifthrow new Exception("The method or operation is not implemented."); }
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public void Clear()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
throw new Exception("The method or operation is not implemented.");
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

发布信息类Data定义如下:

ContractedBlock.gif ExpandedBlockStart.gif Data
None.gifusing System;
None.gif
None.gif
namespace PublisherEngine.Engine
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
public class Data
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
private string _DataID;
InBlock.gif        
public string DataID
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn this._DataID; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gifthis._DataID = value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif        
private string _DataType;
InBlock.gif        
public string DataType
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn this._DataType; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gifthis._DataType = value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif        
private string _Title;
InBlock.gif        
public string Title
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif            
getdot.gifreturn this._Title;}
ExpandedSubBlockStart.gifContractedSubBlock.gif            
setdot.gifthis._Title=value;}
ExpandedSubBlockEnd.gif        }

InBlock.gif        
private string _Content;
InBlock.gif        
public string Content
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn this._Content; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gifthis._Content = value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif        
private string _WebSiteList;
InBlock.gif        
public string WebSiteList
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn this._WebSiteList; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gifthis._WebSiteList = value; }
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

发布信息在MessageQ中以XML格式存在,约定格式为:

None.gif <? xml version = " 1.0 "  encoding = " utf-8 "   ?>
None.gif
< Data >
None.gif    
< datatype ></ datatype >
None.gif    
< dataid ></ dataid >
None.gif    
< title ></ title >
None.gif    
< content ></ content >
None.gif    
< websitelist ></ websitelist >
None.gif
</ Data >

最后是通过Windows Service实现的PublisherEngine。具体代码如下:

ContractedBlock.gif ExpandedBlockStart.gif PublisherEngine
None.gifusing System;
None.gif
using System.Collections.Generic;
None.gif
using System.ComponentModel;
None.gif
using System.Data;
None.gif
using System.Diagnostics;
None.gif
using System.ServiceProcess;
None.gif
using System.Messaging;
None.gif
using System.Text;
None.gif
using System.Xml;
None.gif
using PublisherEngine.Engine;
None.gif
None.gif
namespace PublisherEngine
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
public partial class PublisherService : ServiceBase
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
private IRouterIterator iterator =  new RouterList();
InBlock.gif
InBlock.gif        MessageQueue messageQueue 
= new System.Messaging.MessageQueue();
InBlock.gif        
public PublisherService()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            InitializeComponent();
InBlock.gif            messageQueue.ReceiveCompleted 
+= new ReceiveCompletedEventHandler(messageQueue_ReceiveCompleted);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
protected override void OnStart(string[] args)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
try
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
//可调用webservice获取站点信息,创建RouterList路由集合类
InBlock.gif

InBlock.gif                
string queuePath = "";//从配置文件中获取
InBlock.gif
                messageQueue.Path = queuePath;
InBlock.gif
InBlock.gif                messageQueue.BeginReceive();
ExpandedSubBlockEnd.gif            }

InBlock.gif            
catch (System.Messaging.MessageQueueException ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                Console.WriteLine(ex.Message);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
catch (Exception ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                Console.WriteLine(ex.Message);
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
protected override void OnStop()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
private void messageQueue_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
try
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                Message message 
= messageQueue.EndReceive(e.AsyncResult);
ExpandedSubBlockStart.gifContractedSubBlock.gif                message.Formatter 
= new XmlMessageFormatter(new String[] dot.gif"System.String,mscorlib" });
InBlock.gif
InBlock.gif                DoMessage(message);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
catch (Exception ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                Console.WriteLine(ex.Message);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
finally
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                messageQueue.BeginReceive();
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
private void DoMessage(Message message)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            XmlDocument docMessage 
= new XmlDocument();
InBlock.gif
InBlock.gif            docMessage.LoadXml(message.Body.ToString());
InBlock.gif            XmlNode nodeMessage 
= docMessage.DocumentElement;
InBlock.gif
InBlock.gif            
//解析获取信息nodeMessage,创建data
InBlock.gif
            Data data = new Data();
InBlock.gif
InBlock.gif            iterator.First();
InBlock.gif            
while (iterator.MoveNext())
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                IRouter router 
= iterator.Current;
InBlock.gif                
if (data.WebSiteList.Contains(router.ID))
InBlock.gif                    router.PublishTo(data);
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}


如何应对需求变化

引用李建忠老师教程上一句话:“设计模式描述了软件设计过程中某一类常见问题的一般性的解决方案”。的确,每一种设计模式都是为了解决某一特定问题的,需求的变化会导致解决问题的方法变化,这就要求我们要在设计过程中能尽量适应未来的变化,这也是面向对象程序设计中“封装变化点”的出发点。如果软件设计能一步到位,那么我们讨论设计模式就没有任何意义了。

其实到目前为止,SmartPublisher的设计还没有多少可借鉴之处。但是接下来,我想做一个假设,假设SmartPublisher需要添加以下功能会对以上设计有什么影响。SmartPublisher作为一种网络营销工具,对软件所有者来说,希望能给公司带来新的利润,要求软件需要增加以下功能:
1)对企业会员发布信息进行收费,并不同会员类型有不同的按照收费标准。
普通型会员:企业注册审核通过后即为普通会员,普通型会员发布1条信息按照1分钱/有效站点标准收取。
商务型会员:普通型会员消费满10000元即成为商务型会员,商务型会员发布1条信息按照0.5分钱/有效站点标准收取。
豪华型会员:商务型会员消费满100000元即成为豪华型会员。商务型会员发布1条信息按照0.1分钱/有效站点标准收取。
2)企业会员缴费有三种方式:手机缴费,购买冲值卡,银行转帐。

根据以上需求,我将在上述设计基础上进行,具体设计待续。。。也欢迎各位高手支招。

转载于:https://www.cnblogs.com/ruochen/archive/2008/01/15/1037720.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值