XML在自动收费系统票价表设计中的应用

来源:互联网 发布:qq飞车迈凯轮数据 编辑:程序博客网 时间:2024/05/16 00:31

 

1.      了解复杂度
票价表是自动收费系统中重要的一部分,票价表可以很简单,也可以很复杂。单一票价是最简单的票价形式,票价表为一个设定值就可以了。T型表或矩形表是比较常见的一种票价表,我们在公交车上见到的通常是T型表,其票价主要与乘距有关,格式如下:
起始站/终点站
站1
站2
站3
站N
站1
――
 
 
 
站2
1
――
 
 
站3
1.5
1
――
 
站N
2
1.5
1
――
 
T型表对于非环形线路适用,对于环形线路,上车站和下车站的顺序不同,乘距也有所不同,因此可以使用矩形表:
起始站/终点站
站1
站2
站3
站N
站1
-
1
1.5
3
站2
1
-
1
2
站3
1.5
1
-
1
站N
2
1.5
1
-
 
       T型表或矩形表在非自动收费的系统中使用非常广泛,但在引入自动收费系统后,随着业务规则的复杂化,T型表或矩形表在内容和形式上都很难表示复杂的票价体系。如果说T型表或矩形表表示的是由起始站和终点站两个变量组成的二维票价,自动售票系统中的票价体系可以达到三维以上,增加的维度可以包括:
l         票种:
n         根据持卡人类型不同,可以分为成人卡,老人卡,学生卡,针对不同的票种有不同的定价
n         根据计价方式不同,可以分为计次卡,计费卡和计时卡,计次卡是按乘次进行购买和消费的,计费卡是在卡中存入金额,然后按费用扣费,计时卡是限时段进行发售和消费的。可能还存在计次,计费和计时组合控制的票种。
l         日期,一般对节假日和周末乘车有一定的优惠票价
l         时间,例如可以分为高峰和非高峰时段等,为鼓励非高峰乘车,在票价上进行优惠。
l         优惠方式,存在联乘优惠,尾程优惠,里程/次数奖励等优惠方式,例如对乘车次数超过某个次数后,进行票价优惠
l         系统模式,在某些特定情况下,进行票价优惠或减免,例如系统在晚点,发生事故等情况下进行全系统范围内的优惠。
l         站区的概念,将站组合为站区,对在一个区间内的乘车进行优惠。站区可以通过起始站和终点站来表示。
 
这些都是业主在引入自动收费系统后,根据自身的商业,以及社会效益等综合考虑后,提出的合理的系统要求,不同的业主可能有不同的需求,复杂度也不尽相同,但可以看出,票价体系可能变成一个非常复杂的数据结构。票价的计算也相对复杂:
Amount = F(start_station, end_station, ticket_type, holiday_type, period_type, bonus_type, sys_mode);
其中:
n         Amount:        最终票价
n         start_station 起始站
n         end_station     终止站
n         ticket_type      票种
n         holiday_type   节假日种类
n         period_type     时段种类
n         bonus_type     优惠种类
n         sys_mode       系统模式
 
2.      了解业务规则,制定票价体系
       系统应当支持业主的合理要求,但业主方也应提出具体严格的业务规则,包括:
l         票价的计算方式,是全部采用查表法,还是通过一定的公式计算。如果能够通过公式计算,票价表可以相对简化,只要设备和后台使用相同的公式,那么就可得到相同的票价。但在实际中很少采用公式法,首先因为作为物价的一种,票价表要经过物价部门的审批,所以要有明确的价格表;其次,票价表中不应存在过分小的单位,例如1.98元的单程票,如果有这样的价格,乘客在自动售票机上购买时将无法进行找零。使用公式的时候很难避免这些价格的出现,如果再进行四舍五入等操作,将使系统的清算对帐变得十分困难。因此在大多数自动收费系统中,还是采用查表法,即操作员根据管理部门制定的价格以表格的形式输入系统,使用时通过得到的表格索引得到相应的价格表查找到所需的价格。
l         系统的票种,如果存在不同计价方式的票种,那么票价表与票种的关系在任何情况下都要体现,否则无法进行正确的扣费存在。
l         票价表的维度,即根据哪些因素影响票价的结果。
l         这些因素相互之间的关系,例如优先级,是否组合使用,例如在节假日(日期因素)的高峰时段(时间因素)是否对应一个单独的票价表(组合使用),还是在节假日就不考虑时段了(不组合使用)。
 
只有确定业务关系后,才能着手具体的数据设计和接口设计。例如一个票价规则描述如下:
l         票价表采用查表法。
l         影响票价的因素为:起始站,终点站,节假日,时段,票种,优惠模式,系统模式7中,其中起始站,终点站,票种,优惠模式,系统模式为输入数据(不同的ID),同时可以通过系统提供时间计算节假日和时段的ID。
l         系统中的票种包括计费和计次卡。
l         系统模式仅与票种,起始站,终点站相关,与其它因素无关,而且优先级最高
l         节假日和时段不组合使用,即在节假日就不考虑时段了。
l         优惠模式为积分优惠,由设备得到卡中的积分,并换算为优惠的种类ID。票种和优惠关联,不同的票种,在不同优惠种类下有不同的票价。
l         线路包含环形,即起点和终点互换后,票价可能不同。
l         每个票种都存在缺省票价表,对节假日,时段,优惠模式,系统模式没有符合项的情况,使用票种,起始站,终点站在缺省票价表中取得票价数据。
 
通过上面的业务规则,可以制定以下票价体系
1, 为每个票种建立缺省票价表
2, 判断系统模式,如果处于特殊的系统模式,则通过模式ID和票种ID直接进入相应的票价表;
3, 由节假日和时段得到与时间相关ID,节假日优先
4, 通过票种和优惠模式得到一个组合的卡使用模式ID
5, 通过时间相关ID和卡使用模式ID定位一个票价表(矩形)
6, 在矩形表中,通过起始站和终点站得到最终票价
 
3.      进行数据设计
在简单的票价表中,可以使用定长,不定长或带标记的数据结构表示票价表,对比较复杂的情况,最好使用XML语言来描述。首先根据票价体系模拟出的样本数据如下:
 
<?xml version="1.0" encoding="UTF-8"?>
<fare_system>
   <!--矩形表表示站到站的票价-->
   <fare_tables>
       <fare_table id="1">
          <start id="1">
             <end id="1">1</end>
             <end id="2">2</end>
             <end id="3">3</end>
             <end id="4">4</end>
          </start>
          <start id="2">
             <end id="1">2</end>
             <end id="2">1</end>
             <end id="3">2</end>
             <end id="4">3</end>
          </start>
          <start id="3">
             <end id="1">3</end>
             <end id="2">2</end>
             <end id="3">1</end>
              <end id="4">2</end>
          </start>
          <start id="4">
             <end id="1">4</end>
             <end id="2">3</end>
             <end id="3">2</end>
             <end id="4">1</end>
          </start>
       </fare_table>
       <fare_table id="2">
          <start id="1">
             <end id="1">1.5</end>
             <end id="2">2.2</end>
             <end id="3">3.2</end>
             <end id="4">4.5</end>
          </start>
          <start id="2">
             <end id="1">2.3</end>
             <end id="2">1.3</end>
             <end id="3">2.5</end>
             <end id="4">3.6</end>
          </start>
          <start id="3">
             <end id="1">3.1</end>
              <end id="2">2.2</end>
             <end id="3">1.5</end>
             <end id="4">2.5</end>
          </start>
          <start id="4">
             <end id="1">4.4</end>
             <end id="2">3.2</end>
             <end id="3">2.5</end>
             <end id="4">1.8</end>
          </start>
       </fare_table>
   </fare_tables>
   <!--节假日和周末-->
   <holidays>
       <holiday id="1" start="2006-10-01" end="2006-10-07"/>
       <holiday id="2" start="2006-05-01" end="2006-05-07"/>
       <holiday id="3" start="2006-02-03" end="2006-02-12"/>
   </holidays>
   <!--时段-->
   <periods>
       <period id="1" start="07:00:00" end="09:00:00"/>
       <period id="2" start="17:00:00" end="19:00:00"/>
       <period id="3" start="12:00:00" end="13:00:00"/>
   </periods>
   <!--卡使用类型-->
   <ticket_usages>
       <ticket_usage id="1" ticket_type="0001" bonus="01"/>
       <ticket_usage id="2" ticket_type="0002" bonus="02"/>
       <ticket_usage id="3" ticket_type="0003" bonus="03"/>
       <ticket_usage id="4" ticket_type="0001" bonus="03"/>
       <ticket_usage id="5" ticket_type="0002" bonus="01"/>
       <ticket_usage id="6" ticket_type="0003" bonus="02"/>
   </ticket_usages>
   <!--票种和缺省票价对应表-->
   <ticket_types>
       <ticket_type id="0001">1</ticket_type>
       <ticket_type id="0002">1</ticket_type>
       <ticket_type id="0003">2</ticket_type>
   </ticket_types>
   <!--系统模式到票价表的映射-->
   <get_fare_by_mode>
       <result mode_id="1" ticket_type="0001">1</result>
       <result mode_id="2" ticket_type="0002">2</result>
   </get_fare_by_mode>
   <!--时间和卡使用类型到票价表的映射-->
   <get_fare>
       <result ticket_usage_id="1" time_id="1">1</result>
       <result ticket_usage_id="2" time_id="2">2</result>
       <result ticket_usage_id="3" time_id="3">1</result>
   </get_fare>
</fare_system>
 
根据样本数据生成XML大纲数据
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
   <xs:element name="fare_system">
       <xs:complexType>
          <xs:sequence>
             <xs:element ref="fare_tables"/>
             <xs:element ref="holidays"/>
             <xs:element ref="periods"/>
             <xs:element ref="ticket_usages"/>
             <xs:element ref="ticket_types"/>
             <xs:element ref="get_fare_by_mode"/>
             <xs:element ref="get_fare"/>
          </xs:sequence>
       </xs:complexType>
   </xs:element>
   <xs:element name="fare_table">
       <xs:complexType>
          <xs:sequence>
             <xs:element ref="start" maxOccurs="unbounded"/>
          </xs:sequence>
          <xs:attribute name="id" type="xs:integer" use="required"/>
       </xs:complexType>
   </xs:element>
   <xs:element name="fare_tables">
       <xs:complexType>
          <xs:sequence>
             <xs:element ref="fare_table" maxOccurs="unbounded"/>
          </xs:sequence>
       </xs:complexType>
   </xs:element>
   <xs:element name="get_fare">
       <xs:complexType>
          <xs:sequence>
             <xs:element name="result" maxOccurs="unbounded">
                 <xs:complexType>
                    <xs:simpleContent>
                       <xs:extension base="xs:integer">
                           <xs:attribute name="time_id" type="xs:integer"/>
                           <xs:attribute name="ticket_usage_id" type="xs:integer"/>
                       </xs:extension>
                    </xs:simpleContent>
                 </xs:complexType>
             </xs:element>
          </xs:sequence>
       </xs:complexType>
   </xs:element>
   <xs:element name="get_fare_by_mode">
       <xs:complexType>
          <xs:sequence>
             <xs:element name="result" maxOccurs="unbounded">
                 <xs:complexType>
                    <xs:simpleContent>
                       <xs:extension base="xs:integer">
                           <xs:attribute name="mode_id" type="xs:integer"/>
                           <xs:attribute name="ticket_type" type="xs:integer"/>
                       </xs:extension>
                    </xs:simpleContent>
                 </xs:complexType>
             </xs:element>
          </xs:sequence>
       </xs:complexType>
   </xs:element>
   <xs:element name="holiday">
       <xs:complexType>
          <xs:attribute name="id" type="xs:integer" use="required"/>
          <xs:attribute name="start" type="xs:date" use="required"/>
          <xs:attribute name="end" type="xs:date" use="required"/>
       </xs:complexType>
   </xs:element>
   <xs:element name="holidays">
       <xs:complexType>
          <xs:sequence>
             <xs:element ref="holiday" maxOccurs="unbounded"/>
          </xs:sequence>
       </xs:complexType>
   </xs:element>
   <xs:element name="period">
       <xs:complexType>
          <xs:attribute name="id" type="xs:integer" use="required"/>
          <xs:attribute name="start" type="xs:time" use="required"/>
          <xs:attribute name="end" type="xs:time" use="required"/>
       </xs:complexType>
   </xs:element>
   <xs:element name="periods">
       <xs:complexType>
          <xs:sequence>
             <xs:element ref="period" maxOccurs="unbounded"/>
          </xs:sequence>
       </xs:complexType>
   </xs:element>
   <xs:element name="start">
       <xs:complexType>
          <xs:sequence>
             <xs:element name="end" maxOccurs="unbounded">
                 <xs:complexType>
                    <xs:simpleContent>
                       <xs:extension base="xs:float">
                           <xs:attribute name="id" type="xs:integer"/>
                       </xs:extension>
                    </xs:simpleContent>
                 </xs:complexType>
             </xs:element>
          </xs:sequence>
          <xs:attribute name="id" type="xs:integer" use="required"/>
       </xs:complexType>
   </xs:element>
   <xs:element name="ticket_types">
       <xs:complexType>
          <xs:sequence>
              <xs:element name="ticket_type" maxOccurs="unbounded">
                 <xs:complexType>
                    <xs:simpleContent>
                       <xs:extension base="xs:integer">
                           <xs:attribute name="id" type="xs:integer"/>
                       </xs:extension>
                    </xs:simpleContent>
                 </xs:complexType>
             </xs:element>
          </xs:sequence>
       </xs:complexType>
   </xs:element>
   <xs:element name="ticket_usage">
       <xs:complexType>
          <xs:attribute name="id" type="xs:integer" use="required"/>
          <xs:attribute name="ticket_type" type="xs:integer" use="required"/>
          <xs:attribute name="bonus" type="xs:integer" use="required"/>
       </xs:complexType>
   </xs:element>
   <xs:element name="ticket_usages">
       <xs:complexType>
          <xs:sequence>
             <xs:element ref="ticket_usage" maxOccurs="unbounded"/>
          </xs:sequence>
       </xs:complexType>
   </xs:element>
</xs:schema>
 
当然这个过程也可以反过来,先设计大纲,后生成样本数据,这取决于设计者的习惯和工作流程。
 
4.      确定使用流程
1.         得到模式ID,根据票种ID在get_fare_by_mode中得到票价表ID,然后在相应的票价表中根据起始站和终点站取得票价
2.         如果模式ID为缺省或在get_fare_by_mode中没有取得票价表ID
2.1.             根据系统时间取得节假日ID,如果没有得到,则在时段中取时段ID,都没有取得则使用缺省ID
2.2.             根据票种和优惠取得卡使用种类ID,如果没有则使用缺省ID
2.3.             根据时间ID和卡使用种类ID得到票价表ID
2.4.             在相应的票价表中根据起始站和终点站取得票价
3.         在没有得到票价表ID的情况下,根据票种ID,起始站和终点站使用缺省票价表。
5.      设计数据接口
对票价表的设定和修改者,应提供数据设置的接口,方便数据结构的创建,修改,删除和读取显示。对票价表的使用者应当屏蔽数据结构,仅仅提供一个统一的数据查询接口
 
这样做的好处是:
1, 统一票价表使用方式,避免理解的不同造成使用错误。
2, 减少使用者的工作量,数据结构对使用者透明。
3, 在出现程序错误,或者根据业务变化修改票价表数据结构时,如果接口能够保持不变,则不影响使用者的程序,而且可以做到统一修改。
 
原创粉丝点击