设计模式之策略模式在地铁票价系统中的应用

引言

设计模式是面向对象编程的一个很是精彩的部分。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性,它能帮助咱们将应用组织成容易了解,容易维护,具备弹性的架构。本文经过一个简单的案例来说述策略模式在地铁票价系统中的应用。html

案例描述

乘客从一个车站乘坐地铁到另外一个车站,他/她须要购买一张票。铁路部门对于票价有一些特别的票价规定:git

按照市物价主管部门批复的轨道交通网络票价体系,即:轨道交通实行按里程计价的多级票价,0~6千米3元,6千米以后每10千米增长1元;票价计算采用最短路径法,即:当两个站点之间有超过1条换乘路径时,选取里程最短的一条路径做为两站间票价计算依据。github

案例分析

让咱们考虑有20个站点:1s,2s,3s......20s,而且乘客在不一样的场景下乘坐地铁。为了更清晰的讲述问题,咱们在原有订价标准上虚拟了一些应用场景。算法

  • 若是乘客A乘坐的里程小于6千米,那么他将须要支付3元车票费用。编程

  • 若是乘客B乘坐的里程大于6千米,他将须要额外支付超出部分的车票费用,计费标准为6千米以后每10千米增长1元。设计模式

  • 若是乘客C是VIP客户,那么他将在原计费标准上享受9折优惠。网络

  • 若是后续有一些额外收费或额外优惠,在以上计费基础上再进行调整。架构

解决方案

这个问题能够经过使用“策略设计模式”来解决。由于不一样类型的票价策略能够基于不一样的规则来应用。 如下是票价策略的不一样类型:this

  • 基本票价规则战略
  • VIP票价规则策略
  • 额外的票价规则策略

每张票价规则策略将分别写入票价计算算法,这些算法不会相互干扰。 新的票价规则能够添加和写入新的票价规则策略。这种模式也将遵循“对扩展开放、对修改关闭”的理念。spa

依赖关系图

类图

代码说明

IFareStrategy接口

这个接口定义了票价计算的经常使用策略,实现一个类能够实现基于上下文的票价算法。

using TrainFair.Models;    
namespace TrainFair.FareCalculator  
{  
    public interface IFareStrategy {  
        float GetFare(IFareRule ruleValues, float basicFare);  
    }  
}

FareConstants类
FareConstants定义了计费的规则,包括起步价,超出里程递增价及VIP折扣价。

namespace TrainFair.Constants
{
    public class FareConstants {
        public const float BasicFare = 3.0F;
        public const float OnStationFare = 1.0F;
        public const float VIPDiscount = 0.1F;
    }
}

StationRuleFareCalculator类

StationRuleFareCalculator类根据行驶的车站里程和问题陈述部分定义的一些规则集来计算车费。

using System;  
using TrainFair.Models;  
  
namespace TrainFair.FareCalculator  
{  
    public class StationRuleFareCalculator : IFareStrategy  
    {  
        public float GetFare(IFareRule ruleValues, float basicFare) {  

            var stationFareRuleModel = ruleValues as StationFareRuleModel;  
             if (stationFareRuleModel == null || stationFareRuleModel.StationDistance <= 0.0f)
                return 0;
            
            if (stationFareRuleModel.StationDistance < 6)
                return basicFare;

            int restChargingStations = (int)Math.Ceiling((stationFareRuleModel.StationDistance - 6.0f)/10.0f);
            var totalFare = basicFare + restChargingStations * stationFareRuleModel.IncrementalPrice;           

            return totalFare;
        }  
    }  
}

VIPRuleFareCalculator类
这个类实现的是VIP的票价算法。若是乘客是VIP身份,那么他/她将获得享受特殊的优惠。这个类实现了这个算法。

using TrainFair.Models;  
  
namespace TrainFair.FareCalculator  
{  
     public class VIPRuleFareCalculator : IFareStrategy
    {
        public float GetFare(IFareRule ruleValues, float basicFare) {
            var vipFareRuleModel = ruleValues as VIPFareRuleModel;
            if (vipFareRuleModel == null)
                return 0;
           
            var totalFare = basicFare - (basicFare * vipFareRuleModel.Discount);
            return totalFare;
        }
    }
}

OtherRuleFareCalculator类
这个类实现的是其余额外的费用或优惠票价的算法。一些额外的价格将被添加到总费用中。额外的价格能够是附加收费(正值),也能够是额外折扣(负值)。

using TrainFair.Models;  
  
namespace TrainFair.FareCalculator  
{  
    public class OtherRuleFareCalculator : IFareStrategy
    {
        public float GetFare(IFareRule ruleValues, float basicFare) {
            var otherFareRuleModel = ruleValues as OtherFareRuleModel;
            if (otherFareRuleModel == null)
                return basicFare;

            float totalFare = basicFare + otherFareRuleModel.AdditionalFare;
            return totalFare;
        }
    }
}

FareRuleCalculatorContext类

using TrainFair.Models;  
  
namespace TrainFair.FareCalculator  
{  
    public class FareCalculatorContext {  
  
        private readonly IFareStrategy _fareStrategy;  
        public FareCalculatorContext(IFareStrategy fareStrategy) {  
            this._fareStrategy = fareStrategy;  
        }  
  
        public float GetFareDetails(IFareRule fareRules, float basicFare)  
        {  
            return _fareStrategy.GetFare(fareRules, basicFare);  
        }  
    }  
}

代码结构里有一些基于车站票价,VIP票价,额外票价等状况的model类。

IFareRule接口

这是基本票价规则模型接口,每一个模型类都实现它。

namespace TrainFair.Models  
{  
    public interface IFareRule  
    {  
        int FareRuleId { get; set; }  
    }  
}

StationFareRuleModel类
这个类定义的是车站票价规则的基本属性。

namespace TrainFair.Models  
{  
    public class StationFareRuleModel : IFareRule  
    {  
        public int FareRuleId { get; set; }

        public int  StationsCounts { get; set; }

        public float IncrementalPrice { get; set; }

        public float StationDistance { get; set; }  
    }  
}

VIPFareRuleModel类

这个类定义了VIP折扣的属性。

namespace TrainFair.Models  
{  
    public class VIPFareRuleModel : IFareRule  
    {  
        public int FareRuleId { get; set; }       

        public float Discount { get; set; }
    }  
}

OtherFareRuleModel类

这个类定义其余额外收费的属性。

namespace TrainFair.Models  
{  
    public class OtherFareRuleModel : IFareRule  
    {  
        public int FareRuleId { get; set; }  
  
        public string OtherFareName { get; set; }  
  
        public float AdditionalFare { get; set; }  
    }  
}

模型的属性能够根据将来的需求进行加强和调整,并能够灵活应用在算法类中。

执行结果

如下是控制台输出:

 
本文结尾附上了程序代码。

结语

车站基础票价、VIP票价、额外票价等不一样类型的票价计算规则是不一样的,全部的算法都被分解到不一样的类中,以便可以在运行时选择不一样的算法。策略模式的用意是针对一组算法或逻辑,将每个算法或逻辑封装到具备共同接口的独立的类中,从而使得它们之间能够相互替换。策略模式使得算法或逻辑能够在不影响到客户端的状况下发生变化。说到策略模式就不得不说起OCP(Open Closed Principle) 开闭原则,即对扩展开放,对修改关闭。策略模式的出现很好地诠释了开闭原则,有效地减小了分支语句。

程序代码https://github.com/daivven/TrainFair

 做者: 阿子

 博客地址: http://www.cnblogs.com/yayazi/

 本文地址: http://www.cnblogs.com/yayazi/p/8350679.html  声明:本博客原创文字容许转载,转载时必须保留此段声明,且在文章页面明显位置给出原文链接。
相关文章
相关标签/搜索