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

引言

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

案例描述

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

按照市物价主管部门批复的轨道交通网络票价体系,即:轨道交通实行按里程计价的多级票价,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/

本文地址:http://www.cnblogs.com/yayazi/p/8350679.html

声明:本博客原创文字允许转载,转载时必须保留此段声明,且在文章页面明显位置给出原文连接。

原文地址:https://www.cnblogs.com/yayazi/p/8350679.html

时间: 2024-07-28 22:06:35

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

(四)设计模式之PHP项目应用(策略模式:自动驾驶系统)

1 前言 关于策略模式的定义,模式组成,模式核心思想,模式架构图,程序架构等基础知识介绍.请先参考我的另外一篇博客<(三)设计模式之PHP项目应用(策略模式:商场收银系统)>:http://blog.csdn.net/clevercode/article/details/45722661. 2 项目应用 2.1 需求说明 某公司是福特和本田公司的金牌合作伙伴,现要求开发一套自动驾驶系统,只要汽车上安装该系统就可以实现无人驾驶,只用实现启动,转弯,停止功能即可.该系统可以在福特和本田车上使用.这

【设计模式】策略模式

在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改.这种类型的设计模式属于行为型模式. 在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象.策略对象改变 context 对象的执行算法. 介绍 意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换. 主要解决:在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护. 何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为.

设计模式之策略模式(Strategy)摘录

23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象.创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些具体的类的信息封装起来.第二,它们隐藏了这些类的实例是如何被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以

php设计模式之策略模式

策略模式: 策略模式是对象的行为模式,用意是对一组算法的封装.动态的选择需要的算法并使用. 策略模式指的是程序中涉及决策控制的一种模式.策略模式功能非常强大,因为这个设计模式本身的核心思想就是面向对象编程的多形性思想. 策略模式的三个角色: 1.抽象策略角色 2.具体策略角色 3.环境角色(对抽象策略角色的引用) 实现步骤: 1.定义抽象角色类(定义好各个实现的共同抽象方法) 2.定义具体策略类(具体实现父类的共同方法) 3.定义环境角色类(私有化申明抽象角色变量,重载构造方法,执行抽象方法)

JavaScript设计模式之策略模式(学习笔记)

在网上搜索“为什么MVC不是一种设计模式呢?”其中有解答:MVC其实是三个经典设计模式的演变:观察者模式(Observer).策略模式(Strategy).组合模式(Composite).所以我今天选择学习策略模式. 策略模式:定义了一系列家族算法,并对每一种算法单独封装起来,让算法之间可以相互替换,独立于使用算法的客户. 通常我并不会记得“牛顿第一定律”的具体内容,所以我也难保证我会对这个定义记得多久……用FE经常见到的东西来举个例子说明一下: $("div").animation(

设计模式之策略模式20170720

行为型设计模式之策略模式: 一.含义 策略模式是一种比较简单的模式,也叫做政策模式,其定义如下: 定义一组算法(可抽象出接口),将每个算法都封装起来,并且使它们之间可以互换(定义一个类实现封装与算法切换) 二.代码说明 1.主要有两个角色 1)Context封装角色 它也叫做上下文角色,起承上启下封装作用,屏蔽高层模块对策略,算法的直接访问,封装可能存在的变化. 2)策略角色 该类含有具体的算法 2.在用C实现过程中也是参考这种思想,以压缩,解压算法举例,具体实现如下: 1)策略模式使用场景

如何让孩子爱上设计模式 ——14.策略模式(Strategy Pattern)

如何让孩子爱上设计模式 --14.策略模式(Strategy Pattern) 描述性文字 本节讲解的是行为型设计模式中的第一个模式: 策略模式, 这个模式非常简单,也很好理解. 定义一系列的算法,把每个算法封装起来,并使得他们可以相互替换, 让算法独立于使用它的客户而变化. 一般用来替换if-else,个人感觉是面向过程与面向对象思想的 过渡,这里举个简易计算器的栗子,帮助理解~ 普通的if-else/switch计算器 普通的面向过程if-else简易计算器代码如下: 运行结果如下: 这里我

[design-patterns]设计模式之一策略模式

设计模式 从今天开始开启设计模式专栏,我会系统的分析和总结每一个设计模式以及应用场景.那么首先,什么是设计模式呢,作为一个软件开发人员,程序人人都会写,但是写出一款逻辑清晰,扩展性强,可维护的程序就不是那么容易做到了.现实世界的问题复杂多样,如何将显示问题映射到我们编写的程序中本就是困难重重.另一方面,软件开发中一个不变的真理就是"一切都在变化之中",这种变化可能来自于程序本身的复杂度,也可能来自于客户不断变化的需求,这就要求我们在编写程序中一定要考虑变化的因素,将变化的因素抽离出来,

研磨设计模式之策略模式

策略模式(Strategy) 1  场景问题 1.1  报价管理 向客户报价,对于销售部门的人来讲,这是一个非常重大.非常复杂的问题,对不同的客户要报不同的价格,比如: (1)对普通客户或者是新客户报的是全价 (2)对老客户报的价格,根据客户年限,给予一定的折扣 (3)对大客户报的价格,根据大客户的累计消费金额,给予一定的折扣 (4)还要考虑客户购买的数量和金额,比如:虽然是新用户,但是一次购买的数量非常大,或者是总金额非常高,也会有一定的折扣 (5)还有,报价人员的职务高低,也决定了他是否有权