首页 > 学院 > 开发设计 > 正文

C#编程实践–帮老婆计算产假方案

2019-11-17 02:50:31
字体:
来源:转载
供稿:网友

C#编程实践–帮老婆计算产假方案

2014-10-10 22:57 by 周信达, ... 阅读, ... 评论, 收藏, 编辑

摘要

今天中午午休时,和老婆聊天,老婆还过几天就要请产假了,她在网上问我让我帮她数一下该怎么请假最划算,老婆是个会过日子的人,面对此种要求我当然义不容辞,不过想到这个问题我的第一反应是:这个怎么可以用数的呢?于是,我开始去了解2014年上海市最新的产假政策规定,大致概况如下:“产假加上晚育假一共128天,其中前面98天是正常产假,其中已经包括国家法定节日和双休日,后面30天是晚育假,只包含双休日,不包含国家法定节日,也就是说遇到国家法定节日则假期往后顺延”,注意黑体粗字描述,可以知道这里面的精打细算就体现在前面98天的正常产假。我们要做的就是尽量避免正常产假包含太多的国家法定节假日,否则用老婆的话说那就是“亏”了,注意我把“亏”字打引号,我的意思是在生活中我们不必太过于精打细算斤斤计较,如果过度了那么就容易失去生活情趣和心灵的自由,有句话说吃亏是福。但是,在不妨碍这种前提条件下,我们还是要努力争取,扯远了,这个问题又不复杂,所以,我何乐而不为呢?况且,最近已经准备开始写博了,经常看书看文章看博客,毕竟,纸上得来终觉浅,绝知此事要躬行,还是要经常实践实践,况且作为干这一行的,更要有开放和分享的心态,好了,废话已经很多了,开始代码的构思和实现。

更新

此文已更新,请看这里:C#编程实践--产假方案优化版

领域

初步定位,这是一个关于时间查询的应用,模型围绕时间建立,假期根据月份和日号来表示(公历和农历),另需要提供假期规则的定义,如下(DateModels.cs):

using System;using System.Collections.Generic;using System.Globalization;using System.Linq;using System.Text;using System.Threading.Tasks;namespace HelloBaby{    // 这里提供默认的放假集合定义    public static class DefaultHoliday    {        // 元旦1天假        public static readonly Holiday NewYearsHoliday            = new Holiday(MonthDayDate.NewYearsDay, 1);        // 春节3天假,从前一天(除夕)开始放        public static readonly Holiday SPRingFestivalHoliday            = new Holiday(MonthDayDate.SpringFestival, -1, 3);        // 清明1天假        public static readonly Holiday QingMingHoliday            = new Holiday(MonthDayDate.QingMingDay, 1);        // 劳动节1天假        public static readonly Holiday LabourHoliday            = new Holiday(MonthDayDate.LabourDay, 1);        // 端午节1天假        public static readonly Holiday DragonBoatHoliday            = new Holiday(MonthDayDate.DragonBoatFestival, 1);        // 中秋节1天假        public static readonly Holiday MidAutumnHoliday            = new Holiday(MonthDayDate.MidAutumnDay, 1);        // 国庆节3天假        public static readonly Holiday NationalHoliday            = new Holiday(MonthDayDate.NationalDay, 3);        public static List<Holiday> Holidays = new List<Holiday>{            DefaultHoliday.NewYearsHoliday,            DefaultHoliday.SpringFestivalHoliday,            DefaultHoliday.QingMingHoliday,            DefaultHoliday.LabourHoliday,            DefaultHoliday.DragonBoatHoliday,            DefaultHoliday.MidAutumnHoliday,            DefaultHoliday.NationalHoliday        };    }    // 假期,包含3个成员(农历或公历几月几日?提前几天放?共放几天)    public struct Holiday    {        public Holiday(MonthDayDate monthDay, int startOffset, int days)            : this()        {            MonthDay = monthDay;            StartOffset = startOffset;            Days = days;        }        public Holiday(MonthDayDate monthDay, int days)            : this(monthDay, 0, days)        {        }        public MonthDayDate MonthDay { get; private set; }        public int StartOffset { get; set; }        public int Days { get; set; }        // 根据年份获取假期具体日期枚举        public IEnumerable<DateTime> ToDateTimeRange(int year)        {            DateTime gregorian = DateTime.Now;            if (MonthDay.Calendar == CalendarKind.LunarCalendar)                gregorian = DateUtility.ConvertLunarYearDate(year, MonthDay.Month, MonthDay.Day);            else                gregorian = new DateTime(year, MonthDay.Month, MonthDay.Day);            DateTime begin = gregorian.AddDays(StartOffset);            for (int i = 0; i < Days; i++)            {                yield return begin.AddDays((double)i);            }        }    }    // 此处使用Calendar属性来区分历法    // 也可以将struct改为class使用继承的设计方式,方便扩展    public struct MonthDayDate    {        // 元旦节        public static readonly MonthDayDate NewYearsDay = new MonthDayDate(1, 1);        // 中国春节        public static readonly MonthDayDate SpringFestival =            new MonthDayDate(1, 1, CalendarKind.LunarCalendar);        // 清明节        public static readonly MonthDayDate QingMingDay = new MonthDayDate(4, 5);        // 五一劳动节        public static readonly MonthDayDate LabourDay = new MonthDayDate(5, 1);        // 端午节        public static readonly MonthDayDate DragonBoatFestival =            new MonthDayDate(5, 5, CalendarKind.LunarCalendar);        // 中秋节        public static readonly MonthDayDate MidAutumnDay =            new MonthDayDate(8, 15, CalendarKind.LunarCalendar);        // 国庆节        public static readonly MonthDayDate NationalDay =            new MonthDayDate(10, 1);        public MonthDayDate(int month, int day, CalendarKind calendar)            : this()        {            Month = month;            Day = day;            Calendar = calendar;        }        public MonthDayDate(int month, int day)            : this(month, day, CalendarKind.Gregorian)        {        }        public int Month { get; private set; }        public int Day { get; private set; }        public CalendarKind Calendar { get; private set; }        public static bool Operator ==(MonthDayDate d1, MonthDayDate d2)        {            return d1.Month == d2.Month                && d1.Day == d2.Day                && d1.Calendar == d2.Calendar;        }        public static bool operator !=(MonthDayDate d1, MonthDayDate d2)        {            return !(d1 == d2);        }    }    public enum CalendarKind    {        // 公历(阳历)        Gregorian,        // 中国农历(阴历)        LunarCalendar    }}

注意,在Model里面,我们添加了业务逻辑,比如Holiday的ToDateTimeRange方法里面依赖了外部的农历到公历的转换逻辑,这里依赖了外部逻辑,是否属于不良好的设计?于是我有必要声明,此代码为半实验性代码,非生产代码。既然此处依赖一些外部方法逻辑,那么我也把这部分代码列出(DateUtility.cs):

using System;using System.Collections.Generic;using System.Globalization;using System.Linq;using System.Text;using System.Threading.Tasks;namespace HelloBaby{    public class DateUtility    {        /// <summary>        /// 获取时间段枚举        /// </summary>        public static IEnumerable<DateTime> RangeDay(DateTime starting, DateTime ending)        {            for (DateTime d = starting; d <= ending; d = d.AddDays(1))            {                yield return d;            }        }        /// <summary>        /// 农历转公历        /// </summary>        public static DateTime ConvertLunarYearDate(int year, int month, int day)        {            ChineseLunisolarCalendar calendar = new ChineseLunisolarCalendar();            return calendar.ToDateTime(year, month, day, 0, 0, 0, 0);        }    }}

业务

程序写到这里已经完成了一大半了,接下来就是一些判断的规则逻辑,这里使用扩展方法来实现(DateExtensions.cs):

using System;using System.Collections.Generic;using System.Globalization;using System.Linq;using System.Text;using System.Threading.Tasks;namespace HelloBaby{    public static class DateExtensions    {        /// <summary>        /// 判断日期是否是节假日,使用默认放假规定        /// </summary>        public static bool IsHoliday(this DateTime date)        {            return date.IsHoliday(DefaultHoliday.Holidays);        }        /// <summary>        /// 判断日期是否是节假日,使用指定放假规定        /// </summary>        public static bool IsHoliday(this DateTime date, IEnumerable<Holiday> holidays)        {            return holidays.Any(                d => d.ToDateTimeRange(date.Year).Contains(date)                );        }    }    }

提示:在项目的实践中,我们尽量遵循TDD的开发模式,尤其是针对业务处理层的代码,单元测试代码这里就不贴了,省略掉。

应用

好了,至此我们的领域和业务规则部分已经完成了,可以开始我们的应用了,在一个以数据为中心的年代,有了数据,我们就可以发挥想象,为所欲为,在这里我还是简单的回到最初的问题点上,因为虽然借此机会练练手写写代码,但初衷还是要帮老婆解决问题啊,于是我的应用场景为计算98天产假里面包含的国家法定节日,我在此主要使用LINQ查询:

internal static void PrintSol
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表