您现在的位置是:首页 > cms教程 > Discuz教程Discuz教程

Discuz!NT聚合功能页面程序架构的方法

梁胤鸣2025-07-02Discuz教程已有人查阅

导读鉴于前一阵子所写的关于Discuz!NT文章在园子中有些朋友存在疑惑这里先做一下声明:这些关于Discuz!NT的文章不是要帮助大家把这个项目中所有的程序逻辑都解释一遭

鉴于前一阵子所写的关于Discuz!NT文章在园子中有些朋友存在疑惑这里先做一下声明:这些关于Discuz!NT的文章不是要帮助大家把这个项目中所有的程序逻辑都解释一遭 (我相信大多数朋友也不希望这么做) 而是希望能给大家提供一把“钥匙”,帮助大家从项目结构和程序架构上先对这个产品有一个初步认识,想信只要有过一定开发项目经验的朋友应该从中很快找到突破口,来挖掘出更多对大家有用的东西。当然如果大家认为我写做的方式有什么问题,不妨直接回复,我会根据情况尽力修正的:)
当然这个项目还很不完善(从我个人角度来讲)。所以就更有必然在这里与大家进行交流,我从不认为将更多更优秀的思想集中到这个项目中是什么不好的事情:)只要大家提出的合理的意见,我就会向官方反应。必定开源项目本身就应该有着很好的“人缘”。当然大家可以尽情的批评挑刺,因为很少有什么产品一出来就是优秀的,什么都需要千锤百炼。更合况一个刚发展一年多的婴儿(discuz!nt)。我相信只要大家有足够的爱心和耐心伴随这个婴儿一起成长,并帮助和关注它,就能最终见证开源这种方式在我国的发展轨迹(话说大了)。
好了,不扯了。开始今天的话题吧!
首先把这个聚合项目的架构图放出来,以便在下面的代码解释阶段详加说明:
设计背景:早在RC1之前聚合功能还比较弱化时,系统结构比较简单,只用了一个website类就聚集了大部分的功能调用。但在快速开发完成之后陆续又加入了不少新功能,导致类的名称(website) 与所聚合提供的功能已不完全应用相符 (代码已过度膨胀) ,所以重构的任务已变得非常紧迫了。
但用什么方式,因为系统聚合时是按内容类型来聚合功能页面并决定显示方式的。而这里的内容类型在大概可分为(论坛主题,相册,图片,空间文章(及较新回复)等)。为了尽量简化系统设计时的复杂度,这里只按内容所属的大类(论坛,空间,相册等)来进行简单的初步规划,这就产生出来上面图片所说的类AggregationData,SpaceAggregationData,AlbumAggregationData.cs,ForumAggregationData.cs
看来这里完全可以将它们看为是四个子系统了,同时也可以直接将相应的前台显示控制逻辑与这里面的相关子系统相联,但这就会少了一层封装在里面,另外这四个子系统类 (这里暂且这么说吧之间)如果交互协为也需要有这么一个层以避免直接子系统之间的直接函数调用。
所以这里使用了facade来简单的封装这一层。也就是如下的代码段了:
1 AggregationFacade.cs
2
3 private static AggregationData __baseAggregationData;
4
5 private static ForumAggregationData __forumAggregationData;
6
7 private static SpaceAggregationData __spaceAggregationData;
8
9 private static AlbumAggregationData __albumAggregationData;
10
11 private static PhotoAggregationData __photoAggregationData;
12
13 static AggregationFacade()
14 {
15 __baseAggregationData = new AggregationData();
16
17 __forumAggregationData = new ForumAggregationData();
18
19 __spaceAggregationData = new SpaceAggregationData();
20
21 __albumAggregationData = new AlbumAggregationData();
22
23 __photoAggregationData = new PhotoAggregationData();
24
25 //加载要通知的聚合数据对象,Attach函数将在下面内容中介绍
26 AggregationDataSubject.Attach(__baseAggregationData);
27
28 AggregationDataSubject.Attach(__forumAggregationData);
29
30 AggregationDataSubject.Attach(__spaceAggregationData);
31
32 AggregationDataSubject.Attach(__albumAggregationData);
33
34 AggregationDataSubject.Attach(__photoAggregationData);
35 }
而前端显示页面的数据对象获取将通过如下属性进行相关的操作和调用。
1 public static ForumAggregationData ForumAggregation
2 {
3 get
4 {
5 return __forumAggregationData;
6 }
7 }
目前已设计了数据读取时所使用的逻辑(相关的聚合数据类),但如果通过进程去更新相应的已加载的数据 (因为在discuz!nt中的数据要考虑跨进程数据同步)。同时因为要更新的内容又过于繁杂,所以要使用一种机制来解决这个问题。
这里我使用了Observer来尝试解决这个问题。这里不妨将这个模式的图放在这里:同时也有系统中所使用的相应设计如下,便于大家进行对比。好的,而相关的模式实现代码如下(AggregationDataSubject类中):
1 #region 采用Observer模式清空当前进程中的聚合数据
2
3 private static ArrayList __aggregationDataArrayList = new ArrayList();
4
5
6 //调用在AggregationFacade类的静态构造函数中
7 public static void Attach(AggregationData __aggregationData)
8 {
9 __aggregationDataArrayList.Add(__aggregationData);
10 }
11
12 public static void Detach(AggregationData __aggregationData)
13 {
14 __aggregationDataArrayList.Remove(__aggregationData);
15 }
16
17 public static void NotifyClearDataBind()
18 {
19 foreach (AggregationData __aggregationData in __aggregationDataArrayList)
20 {
21 __aggregationData.ClearDataBind();
22 }
23 }
24
25 #endregion
而调用Attach的函数 (初始化要操作的对象数组) 在AggregationFacade的静态构造函数中。上面已加了说明:)
另外在这个类中还使用了定时器来定时检查相关数据文件中的修改日期,如果为真则调用数组中对象的ClearDataBind()方法以便让相关的数据对象为null,相关逻辑如下
1 //设置定时器时间为15秒
2 private static System.Timers.Timer aggregationConfigTimer = new System.Timers.Timer(15000);
3
4 //AggregationDataSubject类的静态构造函数
5 static AggregationDataSubject()
6 {
7
8 //初始化定时器
9 aggregationConfigTimer.AutoReset = true;
10 aggregationConfigTimer.Enabled = true;
11 aggregationConfigTimer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
12 aggregationConfigTimer.Start();
13 }
14
15 private static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
16 {
17 if (IsFileHadRewrite())
18 {
19 //重设文件修改时间,以便下次文件更新时进行逻辑判断
20 ReSetFileChangeTime();
21
22 //重新从数据文件中读取数据
23 AggregationData.ReadAggregationConfig();
24
25 //调用上面的相关函数
26 NotifyClearDataBind();
27 }
28 }
这样当后台修改任何聚合数据页面 (aggregation.config) 的数据后,都会使aggregation.config文件被更新(文件修改时间会发生变化)。
这时前台页面调用数据时就会根据这个判断来决定是从数据文件或数据库中重新加载数据还是使用已初始化的数据了。
这里为了说明只举了一个例子,其实这样的程序逻辑在这个项目文件中有不少.
1 private DataTable topNComment;
2 public DataTable GetSpaceTopCommentsFromFile()
3 {
4 //注意此处的判断
5 if (topNComment != null)
6 {
7 return topNComment;
8 }
9
10 //从文件中取
11 topNComment = aggregationDS.Tables["topncommentspace"];
12
13
14 return topNComment;
15 }
为什么使用这样的方式呢。其实是出现进程并发时效率的考虑,因为之前的程序逻辑是当HTTP请求到来时程序会去判断数据文件是否更新并决定是否从新加载较新的数据信息。但当我们在官方使用这种逻辑后却发现当并发上来时(50人在线),就出现了对象引用为空的情况。而纠其原因就要频繁的磁盘IO访问导致程序运行速度的下降。后来在一个偶然的条件下我想起了可以用定时器将数据进行按时加载定制,才使用这种方式。必定现在数据访问与数据更新从偶合在一起变成了相互分离,互不影响。且在后来基本上就没再出现前面所说的对象引用为空的问题。所以在这里就直接借签了这种方式。 (当然大家如果有什么更好的方式,不妨在这里聊上一聊:)
这样这个项目中的主要架构已全部说明完了。而相关的调用数据库的逻辑大家只要 reflactor或等官方提供源码下载一看便知.题外话:
其实这里还有一种思想要与大家交流,那就是设计模式是否该在项目的详细设计阶段(类图)出现前后就该确定下来?
说实话,以前我的软件设计理念是只要对行业有足够的了解和对用户需求把握的够精确就可以使用模式来分解设计时出现的复杂度和降低类之间的耦合系数。必定有系统架构师这个职位在做这方面的工作(当然这个职位还有其它重要的职责)。但极限编程中所说的过度工程(over-engineering)所描述的残酷现实又让这种过早出现的设计“ ”荡然无存。必定“对完美的追求无法写出实用的代码,而实用是软件压倒一切的要素”

本文标签:

很赞哦! ()

相关源码

  • (PC+WAP)蓝色智能环保机械设备网站营销型pbootcms模板下载本模板基于PbootCMS系统开发,为环保设备制造企业设计,特别适合展示环保机械、智能装备等产品。采用响应式技术,确保各类设备参数和技术方案在不同终端上都能清晰展示。查看源码
  • 帝国cms7.5游戏门户H5小游戏网站模板源码免费下载基于帝国CMS7.5开发的H5游戏门户模板,为在线游戏平台设计。支持PC端与移动端同步生成,打造完整的游戏娱乐体验平台。查看源码
  • (自适应)品牌创意设计作品工作室pbootcms模板下载该模板适用于品牌策划、艺术设计、广告创意公司官网,亦可通过替换图文快速适配其他行;高端创意设计公司工作室网站源码极简代码架构、艺术化视觉布局、企业级功能扩展性。查看源码
  • (自适应)绿色农业机械设备农场网站源码下载为现代农业机械领域打造的响应式网站模板,采用PbootCMS内核开发,数据实时同步后台管理。通过简洁大气的视觉设计,有效展示农机产品技术参数与应用场景,帮助客户快速建立专业数字化形象。查看源码
  • (PC+WAP)历史复古古典古籍文章资讯类pbootcms模板下载本模板基于PbootCMS系统开发,为古籍研究、历史文献类网站设计,特别适合展示古典书籍、历史档案等文化内容。采用复古风格设计,同时具备现代化响应式布局,确保在PC和移动设备上都能呈现优雅的阅读体验。查看源码
  • (自适应响应式)投资理财金融机构财务管理pbootcms模板本模板基于PbootCMS系统开发,为投资理财、金融机构等行业设计。采用专业严谨的布局风格,突出金融服务行业特色,适合展示各类理财产品、投资服务和金融资讯。查看源码
分享笔记 (共有 篇笔记)
验证码:

本栏推荐