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

2023-11-06 16:32

本文主要是介绍设计模式之策略模式在地铁票价系统中的应用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

引言

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

案例描述

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

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

案例分析

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

  • 如果乘客A乘坐的里程小于6公里,那么他将需要支付3元车票费用。

  • 如果乘客B乘坐的里程大于6公里,他将需要额外支付超出部分的车票费用,计费标准为6公里之后每10公里增加1元。

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

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

解决方案

这个问题可以通过使用“策略设计模式”来解决。因为不同类型的票价策略可以基于不同的规则来应用。 以下是票价策略的不同类型:

  • 基本票价规则战略

  • VIP票价规则策略

  • 额外的票价规则策略

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

依赖关系图

类图

代码说明

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/p/8350679.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

这篇关于设计模式之策略模式在地铁票价系统中的应用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/357778

相关文章

Go语言实现桥接模式

《Go语言实现桥接模式》桥接模式是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立地变化,本文就来介绍一下了Go语言实现桥接模式,感兴趣的可以了解一下... 目录简介核心概念为什么使用桥接模式?应用场景案例分析步骤一:定义实现接口步骤二:创建具体实现类步骤三:定义抽象类步骤四:创建扩展抽象类步

SQL 注入攻击(SQL Injection)原理、利用方式与防御策略深度解析

《SQL注入攻击(SQLInjection)原理、利用方式与防御策略深度解析》本文将从SQL注入的基本原理、攻击方式、常见利用手法,到企业级防御方案进行全面讲解,以帮助开发者和安全人员更系统地理解... 目录一、前言二、SQL 注入攻击的基本概念三、SQL 注入常见类型分析1. 基于错误回显的注入(Erro

Nginx内置变量应用场景分析

《Nginx内置变量应用场景分析》Nginx内置变量速查表,涵盖请求URI、客户端信息、服务器信息、文件路径、响应与性能等类别,这篇文章给大家介绍Nginx内置变量应用场景分析,感兴趣的朋友跟随小编一... 目录1. Nginx 内置变量速查表2. 核心变量详解与应用场景3. 实际应用举例4. 注意事项Ng

Java中的随机数生成案例从范围字符串到动态区间应用

《Java中的随机数生成案例从范围字符串到动态区间应用》本文介绍了在Java中生成随机数的多种方法,并通过两个案例解析如何根据业务需求生成特定范围的随机数,本文通过两个实际案例详细介绍如何在java中... 目录Java中的随机数生成:从范围字符串到动态区间应用引言目录1. Java中的随机数生成基础基本随

C++简单日志系统实现代码示例

《C++简单日志系统实现代码示例》日志系统是成熟软件中的一个重要组成部分,其记录软件的使用和运行行为,方便事后进行故障分析、数据统计等,:本文主要介绍C++简单日志系统实现的相关资料,文中通过代码... 目录前言Util.hppLevel.hppLogMsg.hppFormat.hppSink.hppBuf

C++中的解释器模式实例详解

《C++中的解释器模式实例详解》这篇文章总结了C++标准库中的算法分类,还介绍了sort和stable_sort的区别,以及remove和erase的结合使用,结合实例代码给大家介绍的非常详细,感兴趣... 目录1、非修改序列算法1.1 find 和 find_if1.2 count 和 count_if1

Redis中群集三种模式的实现

《Redis中群集三种模式的实现》Redis群集有三种模式,分别是主从同步/复制、哨兵模式、Cluster,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1. Redis三种模式概述2、Redis 主从复制2.1 主从复制的作用2.2 主从复制流程2

深入理解MySQL流模式

《深入理解MySQL流模式》MySQL的Binlog流模式是一种实时读取二进制日志的技术,允许下游系统几乎无延迟地获取数据库变更事件,适用于需要极低延迟复制的场景,感兴趣的可以了解一下... 目录核心概念一句话总结1. 背景知识:什么是 Binlog?2. 传统方式 vs. 流模式传统文件方式 (非流式)流

Redis中删除策略的几种实现方式

《Redis中删除策略的几种实现方式》本文详细介绍了Redis的过期键删除策略和内存淘汰策略,过期键删除策略包括定时删除、惰性删除和定期删除,具有一定的参考价值,感兴趣的可以了解一下... 目录前言一、设计背景:为什么需要删除策略?二、第一类:过期键的 3 种核心删除策略1. 定时删除(Timed Dele

前端缓存策略的自解方案全解析

《前端缓存策略的自解方案全解析》缓存从来都是前端的一个痛点,很多前端搞不清楚缓存到底是何物,:本文主要介绍前端缓存的自解方案,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、为什么“清缓存”成了技术圈的梗二、先给缓存“把个脉”:浏览器到底缓存了谁?三、设计思路:把“发版”做成“自愈”四、代码