多样式星期名字转换

上传人:子 文档编号:41440527 上传时间:2018-05-29 格式:DOC 页数:23 大小:58KB
返回 下载 相关 举报
多样式星期名字转换_第1页
第1页 / 共23页
多样式星期名字转换_第2页
第2页 / 共23页
多样式星期名字转换_第3页
第3页 / 共23页
多样式星期名字转换_第4页
第4页 / 共23页
多样式星期名字转换_第5页
第5页 / 共23页
点击查看更多>>
资源描述

《多样式星期名字转换》由会员分享,可在线阅读,更多相关《多样式星期名字转换(23页珍藏版)》请在金锄头文库上搜索。

1、多样式星期名字转换多样式星期名字转换| 李天平整理 | 天道酬勤 多样式星期名字转换 Design, C#1. 原来的问题.Johnsuna 在我的关于枚举的种种 C#, IL, BCL那里提出了这样一个问题:现在我想做一个多版本的带农历的中国万年历,月历中有星期日、星期一至六,我想使用“星期一“,“一“或“Monday“, “Mon“,或“M“,但也可能使用其组合,如“星期一 Mon”, 于是我定义一个公共Style 枚举,里面有 ChineseFullName, ChineseShortName, EnglishFullName,EnglishShortName, EnglishSingl

2、eLetter 等,然后又定义一个公共的 ChineseFullName 枚举,里面有:星期一,星期二等等,类似的 EnglishShortName:Mon,Tue 等(类推) 。 因为可能要进行组合,比如 Style 为:ChineseFullName|EnglishShortName 以便得到“星期一 MON”的结果,所以考虑使用枚举而未使用数组。 我的问题是: 如果现在选择的是星期五,Style 样式为 EnglishShortName,如何取得“Fri”的字符串?如果样式 Style 选择的是 EnglishShortName | ChineseShortName,又如何得到“Fri

3、一”呢? 如果 EnglishSingleLetter 枚举,则其枚举值为:M,T,W,T,F,S,S,很明显,T(Tuesday)与 T(Thursday)重复,S(Saturday)与S(Sunday)重复,这在枚举中是不允许的。那么,如何才能正确实现呢?2. 正向方案:实施授权。根据 Johnsuna 的需求,我们得首先有一个 DayStyle 枚举来表示各种可用样式的名字,由于需求明确提出要进行样式的复合表示,所以我们必须在枚举上加上 FlagsAttribute:/ Code #01Flagsenum DayStyleChineseFullName = 0x0001,ChineseS

4、hortName = 0x0002,EnglishFullName = 0x0004,EnglishShortName = 0x0010,EnglishSingleLetter = 0x0020,补充阅读:如果你不知道我为什么这样为 DayStyle 的成员设值,你可以看看我的关于枚举的种种 C#, IL, BCL ,我在文章讲述了位枚举的值的设置以及相关注意事项。下面,我将采用 TDD 的思维一步一步探讨这个问题的解决方案。首先,根据上面的需求,我认为 Johnsuna 会喜欢下面这种做法:/ Code #02textBox1.Text = day.ToString(DayStyle.Chi

5、neseFullName |DayStyle.ChineseShortName |DayStyle.EnglishFullName |DayStyle.EnglishShortName |DayStyle.EnglishSingleLetter);上面这种方法很明显需要我们在 ToString 里面分析客户端把一个什么样的 DayStyle 传递进来了,当然包括单独一个 DayStyle 成员以及通过“|”运算符得到的成员组合这两种情况。我们知道,当某个位枚举变量和某一位枚举成员的按位与操作结果不为零时,该变量包含了该枚举成员。这样,下面的代码可以放到 ToString 里面用于进行与 Chi

6、neseFullName 相关的操作:/ Code #03if (style if (style 补充阅读:关于字符串的常见操作以及与之相关的性能问题,我推荐你阅读我所翻译的 Performance considerations for strings in C#,该文比较了直接在 String 对象上执行这些操作和使用 StringBuilder 来执行这些操作在性能上的不同表现,并且从定量的角度给出了一个用于判断使用哪种方法来执行这些常见操作的参考标准。然而,上面的代码仅能用于示意,它不能真正用到实际中,为什么呢?很明显,如果我们硬编码这些星期的表示,那么 ToString 至少还需要一个

7、参数来判断客户端需要星期几的表示。这个方案除了加重了我们的劳动强度让我们有借口叫老板加工资外,它几乎没有其他好处了。所以,我们必须想办法把这个“星期几”的具体表示分离出来。如何做到呢?很明显,Template Method 模式是一个让我们的繁重工作得到解脱的办法。现在,我们要做的就是声明一个抽象类 Day 以及一系列的抽象方法,例如 ToChineseFullName,让 Day 的派生类,例如 Monday,实现这一组抽象方法,而 Day.ToString 就通过这一组抽象方法把获取具体的表示的工作“授权”给那些派生类:/ Code #05protected abstract string

8、 ToChineseFullName();public string ToString(DayStyle style)if (style / 好吧,现在万事俱备,只欠子类了:/ Code #06class Monday : Dayprotected override string ToChineseFullName()return “星期一“;/ 好了,剩下的工作就是如法炮制其他派生类,虽然这些工作是劳动密集型的,但你仍得着手完成它。下面是 Monday 的实现:正向方案#region 正向方案using System;using System.Collections.Generic;usin

9、g System.Text;namespace MyUtils.Dayclass Programstatic void Main(string args)Day day = new Monday();Console.WriteLine(day.ToString(DayStyle.ChineseFullName |DayStyle.ChineseShortName |DayStyle.EnglishFullName |DayStyle.EnglishShortName |DayStyle.EnglishSingleLetter);public abstract class Dayprivate

10、StringBuilder m_Content = new StringBuilder();protected abstract string ToChineseFullName();protected abstract string ToChineseShortName();protected abstract string ToEnglishFullName();protected abstract string ToEnglishShortName();protected abstract string ToEnglishSingleLetter();public string ToSt

11、ring(DayStyle style)if (style if (style if (style if (style if (style return m_Content.ToString();public override string ToString()return ToString(DayStyle.ChineseFullName);public class Monday : Dayprotected override string ToChineseFullName()return “星期一“;protected override string ToChineseShortName

12、()return “一“;protected override string ToEnglishFullName()return “Monday“;protected override string ToEnglishShortName()return “Mon“;protected override string ToEnglishSingleLetter()return “M“;Flagspublic enum DayStyleChineseFullName = 0x0001,ChineseShortName = 0x0002,EnglishFullName = 0x0004,Englis

13、hShortName = 0x0010,EnglishSingleLetter = 0x0020,#endregion值得注意的是,我在 Day 中重载了 Object.ToString 方法,因为我不希望在任何可能隐式调用 Object.ToString 的地方得到一个类型的名字。你可以把这个重载后的版本看作是默认的样式表示转换,套用任何一个你喜欢的转换策略。3. 后来的问题.上面那个方案可行,但就是不好,因为它隐藏了一个炸弹,一旦这个炸弹爆炸,我们不但没借口向老板提出加工资,还要受老板责怪,并且要自己加班收拾残局。你能猜到这个炸弹是什么吗?让我们回顾一下 DayStyle 枚举,这个枚举现

14、在表明我们将可以处理两种语言,并且每种语言至少有两种表达方式,你是否想到了什么呢?如果我们现在要加多一种语言呢?问题就在这里了,这个枚举的成员不够稳定。现在我们已经要处理中文和英文两种语言了,将来难免要处理更多的语言,因为你可能希望你的程序面向国际市场。更糟糕的是,我们并不知道我们将要添加的语种有多少种表达方式,至少现在的情况是英语比汉语多了一个“首字母”表达方式,那么有谁又能知道将要添加的语中会带有哪些稀奇古怪的特殊表达方式呢?很明显,DayStyle 枚举的不稳定将会扩散到与之相关的每一个角落,而维护这样的代码可能会变成一场噩梦。如果你读过 Alan Shalloway 和 James R

15、. Trott 的 Design Patterns Explained,你应该会记得他们对封装的精辟阐述:Find what is varying and encapsulate it.接下来,我将会尝试把变化的根源封装起来.4. 反向方案:封装变化。如果你读过我关于枚举的文章,你会知道我主张把枚举看作一种分类手段,并且仅当分类的细节相对稳定的情况下才考虑使用枚举,否则你应该考虑别的出路。那么,在我们要处理的问题域中,哪些因素容易改变,哪些因素又较为稳定呢?很明显,DayStyle 绝对不会被归入稳定因素的行列,于是剩下的就是 Day 了,那么 Day 稳定吗?当然稳定,因为一个星期有且仅有

16、7 天,并且每天的名字也是固定的。那么,把 Day 表示成枚举就合适了:/ Code #07enum DaySunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,下面,我也将采用 TDD 的思维来一步一步探讨该问题的解决方案。由于我不知道 Johnsuna 会否喜欢上这个方案,我只能假设有一个喜欢这个方案的用户 Foo 了。既然 Foo 喜欢这个方案,他将很有可能使用如下方式来处理转换:/ Code #08NameConverter nc = new NameConverter();nc.AddInnerNameConverters(new ChineseFull

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 生活休闲 > 科普知识

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号