编程漫谈——高速铁路客运服务计划编制问题的领域设计


title: 编程漫谈——高速铁路客运服务计划编制问题的领域设计
date: 2018-09-23 16:48:11
tags:

  • 团队workshop
    categories:
  • 编程漫谈

  本文是我在2018年9月团队Workshop上所讲内容的底稿。为方便各位同学学习交流,发布于此。Slide

引言

  在上一次的漫谈中,我结合团队的研究方向,对我们要开发的计算机软件进行了需求分析。目前来看,我们想要通过编程解决两个问题:

  • 信息管理 —— 我们需要维护,管理,可视化基础数据
  • 算法实现 —— 我们需要将科研当中的算法运用到实际的案例上

  实现上述两个功能在程序的设计上带来了巨大的挑战。因为我们希望开发出的软件具有良好的可维护性代码可读性。具体说来,就是将算法实现和信息管理功能彻底解耦。

  举例来说,在公交系统中,一个网络弧段通常用一系列字段描述: 前序弧段后续弧段...设计速度道路宽度道路长度。在铁路网络中,网络弧段的描述则是:前序弧段后续弧段运营速度长度坡度信号制式。如果我们要在这个两种网络当中实现最短路算法,我们希望这个算法只写一遍(尽量减少冗余代码)。事实上,我们研究的问题不止一个,而提出的算法更多,我们希望能把这些工作整理在一个程序中,同时,考虑到以后的研究,我们希望这个程序能够减少未来的工作量。这个问题属于软件工程的研究范畴。为了解决我们的问题,下面我要引入一些软件工程上的方法论。

Domain-Driven Design (DDD) 领域模型驱动设计

  为了解决复杂软件设计的问题,Eric Evans 在《领域驱动设计——软件核心复杂性应对之道》中详细介绍了DDD设计思想。从我的个人理解出发,DDD模式以业务逻辑(领域)为核心进行软件设计,注重对业务的划分,聚合,而对资源的操作用Repository封装。这样做的好处是显而易见的——我们可以把注意力集中在业务逻辑上。

  DDD模式将软件系统分为四层:基础结构层、领域层、应用层和表现层,层与层之间的依赖关系如下图所示。在领域层中,我们只需要完成对业务设计就好,至于其中所用到的数据的读写则是基础设施层需要实现的。介绍DDD的设计思想不是本文的重点,下面我们着重介绍如何对目前我的研究问题进行建模。


1.png

高速铁路客运服务网模型

  在对铁路客运服务网的研究当中,主要要素包含:物理网络,开行方案, 运行图(宏观)以及活动设备计划(e.g. 交路计划)。而我们团队主要研究的问题包括:

  • 开行方案编制问题
  • 宏观运行图编制问题
  • 动车组交路编制及检修问题
  • 客流预测问题

  在过去十多年的研究当中,在以上这些问题的研究中,我们提出了很多模型及算法。再次强调的是,我们的目标是将这些模型与算法在统一的平台实现。注意:大家的模型和算法基于的具体实例可以是不同的(例如前面所论述的公交与铁路的例子),但是大家的问题输入与输出基本相同。为了解开数据管理与问题求解之间的耦合,首先需要划分模块并设计接口。这样做的好处是编制算法的时候我们并不需要网络的很多细节,而修改路网的某些字段也不会对算法运行造成影响。

基础路网

  基础路网的元素包含:路网,线路,车站和区间。这里为了结合运输计划的建模,我把物理路径也放到了这一层。

  • 路网

    public interface IRailwayNetwork
    {
        IEnumerable<IRailwaySection> SectionCollection { get; } //区间集合
        IEnumerable<IRailwayStation> StationCollection { get; } //车站集合
        IEnumerable<IRailwayLine> LineCollection { get; } //线路集合
    }
    
  • 车站

    public interface IRailwayStation
    {
        int RailwayStationID { get; }
        string StaName { get; }
    }
    
  • 区间

    public interface IRailwaySection
    {
        int RailwaySectionID { get; }
        string RailwaySectionName { get; }
        IRailwayStation StartSta { get; }
        IRailwayStation EndSta { get; }
    }
    
  • 线路

    public interface IRailwayLine
    {
        int RailwayLineID { get; set; }
        IEnumerable<IRailwaySection> RailwaySections { get; }
        IEnumerable<IRailwayStation> RailwayStations { get; }
    }
    
  • 物理网路径

    public interface IRailwayNetRoute
    {
        IEnumerable<IRailwaySection> AlongSectionList { get; } // 区间列表
        IEnumerable<IRailwayStation> AlongStaList { get; } // 途径车站列表
    }
    

运输计划模型

  这里以开行方案为例展示如何对运输计划进行设计。注意,运输计划需要基于路网对象实例的。也就是说,当我们提到"北京西站"的时候,是指特定的一个车站对象。

  • 方案线

    public interface ILine
    {
        string Name { get; } // 方案线名称
        IRailwayNetRoute Route { get; } // 物理路径
        IEnumerable<IRailwayStation> StopStations { get; } // 停站车站集合
    }
    
  • 开行方案

    public interface ILineLlan: IEnumerable<ILine>
    {
        string Name { get; }
    }
    

  运行图??交路??

客运需求模型

  ???

问题-求解器模型

  上面的建模解决的是问题的输入—输出的表达一致性问题。但是这并不是问题的全部,在DDD模式中,我们需要找到适合的聚合根 (Aggregated Root) 完成对数据的读取/存储。问题环境 (Problem Data Context) 就是这样的一个聚合根。它包含一个问题的所有输入,以运行图编制问题为例,Data Context包含以下内容。

public interface ITTPDataContext // TTP问题环境
{
    IRailwayNetwork Net { get; set; } // 物理网络
    ILineLlan LinePlan { get; set; } // 开行方案
    double ArrArrHeadway(IRailwayStation sta); // 到-到间隔
    double DepDepHeadway(IRailwayStation sta); // 发-发间隔
    double LowerBoundDwellingTimeInStation(ILine l, IRailwayStation sta); // 最小停站时间
    double UpperBoundDwellingTimeInStation(ILine l, IRailwayStation sta); // 最大停站时间
    double LowerBoundRunningTimeInSection(ILine l, IRailwaySection sec); // 最小区间运行时间
    double UpperBoundRunningTimeInSection(ILine l, IRailwaySection sec); // 最大区间运行时间
    double LowerBoundStartTime(ILine l); // 最早发车时间
    double UpperBoundStartTime(ILine l); // 最晚发车时间
}

  另一方面,问题的求解也需要封装起来便于调用。对于一类问题环境,我们可以设计一个求解器,典型的问题求解器如下。

public class TTPSolver
{
    public virtual ITTPDataContext DataContext { get; set; }

    public ITimeTable Solve()
    {
        // Solution Method Code
        // ...
        // ...
    }
}

  应用层主要可以通过以下步骤来求解问题:

  1. 从Repository 生成 Data Context

  2. 调用 Solver 求解问题。

    简单的代码示例如下:

public OperationResponse GenTimeTable(string wsName)
{
    //Some codes...
    RailwayNetwork net = NetRepos.Network;  //NetRepos是路网的Repostory
    LinePlan p = TTPRepos.GenLinePlan(wsName, net); //TTPRepos是运行图编制问题输入的Repostory
    ITTPDataContext ctx = TTPRepos.GenCtx(wsName);
    TTPSolver solver = new TTPSolver
    {
        Net = net,
        LinePlan = p,
        DataContext = ctx,
        TTBuilder = new TimetableBuilder()
    };
    solver.Solve();
    //Some codes...
}

总结

  本文主要介绍了DDD模式下设计高速铁路客运服务网的一些细节。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,094评论 1 32
  • 设计模式分类 总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原...
    lifeline丿毅阅读 1,204评论 0 2
  • title: 编程漫谈——问题,套路与工具date: 2017-12-27 13:21:11tags: 心得cat...
    面包_y阅读 327评论 0 0
  • 创业就是玩游戏,打怪升级弄装备,整天为了游戏币斤斤计较,其实这玩意儿生不带来,死不带去,若是有一天不玩了,会觉得挺...
    徐呆瓜阅读 394评论 0 2
  • 我每天就被这样一群天使爱着,他们不愿意你离开,会想要你陪着,会吃其他人的醋。我都被惯坏了……想着又一年毕业季...
    d3058123fc87阅读 179评论 0 0