(续上篇)
         “到底如何去改良策略模式呢?”小菜恳切地问道。
         “你仔细观察过没有,你的代码,不管是用工厂模式写的,还是用策略模式写的,那个分支的switch依然去不掉。原因在哪里?”大鸟反问道。
          “因为程序里有下拉选择,用户是有选择的,那么程序就必须要根据用户的选择来决定实例化哪一个子类对象。无论是在客户端窗体类编程还是到工厂类里编程,这个switch总是少不掉的。问题主要出在这里。”小菜十分肯定的说。
         “是呀,”大鸟道,“所以我们要考虑的就是可不可以不在程序里写明‘如果是打折就去实例化CashRebate类,如果是返利就去实例化CashReturn类’这样的语句,而是在当用户做了下拉选择后,再根据用户的选择去某个地方找应该要实例化的类是哪一个。这样,我们的switch就可以对它说再见了。”
        “听不太懂哦,什么叫‘去某个地方找应该要实例化的类是哪一个’?’小菜糊涂地说
        “,我要说的就是一种编程方式:依赖注入(Dependency Injection),从字面上不太好理解,我们也不去管它。关键在于如何去用这种方法来解决我们的switch问题。本来依赖注入是需要专门的IoC容器提供,比如spring.net,显然当前这个程序不需要这么麻烦,你只需要再了解一个简单的.net技术‘反射’就可以了。”
        “大鸟,你一下子说出又是‘依赖注入’又是‘反射’这些莫名其妙的名词,我有点晕哦!”小菜有些犯困,“我就想知道,如何向switch说bye-bye!至于那些什么概念我不想了解。”
        “心急讨不了好媳妇!你急什么?”大鸟嘲笑道,“反射技术看起来很玄乎,其实实际用起来不算难。”

“请看下面的两个样例:

1//实例化方法一   
2//原来我们把一个类实例化是这样的
3Animal animal=new Cat();  //声明一个动物对象,名称叫animal,然后将animal实例化成猫类的对象
4
5//实例化方法二
6//我们还可以用反射的办法得到这个实例
7using System.Reflection;//先引用System.Reflection
8//假设当前程序集是AnimalSystem,名称空间也是AnimalSystem
9Animal animal = (Animal)Assembly.Load("AnimalSystem").CreateInstance("AnimalSystem.Cat");

其中关键是

Assembly.Load("程序集名称").CreateInstance("名称空间.类名称")

那也就是说,我们可以在实例化的时候,再给计算机一个类的名称字符串,来让计算机知道应该实例化哪一个类。”大鸟讲解道。
       “你的意思是,我之前写的‘cc.setBehavior(new CashNormal());’可以改写为‘cc.setBehavior((CashSuper)Assembly.Load("商场管理软件").CreateInstance("商场管理软件.CashNormal")’,不过,这只不过是换了种写法而已,又有什么神奇之处呢?”小菜依然迷茫。
        “分析一下,原来new CashNormal()是什么?是否是写死在程序里的代码,你可以灵活更换吗?”大鸟问。
        “不可以,那还换什么,写什么就是什么了呗。”
        “那你说,在反射中的CreateInstance("商场管理软件.CashNormal"),可以灵活更换‘CashNormal’吗?”大鸟接着问。
        “还不是一样,写死在代码…………等等,哦!!!我明白了。”小菜一下子顿悟过来,,兴奋起来。“因为这里是字符串,可以用变量来处理,也就可以根据需要更换。哦,My God!太妙了!”
       “哈哈,博客园中的有篇博文《四大发明之活字印刷——面向对象思想的胜利》中曾经写过,‘体会到面向对象带来的好处,那种感觉应该就如同是一中国酒鬼第一次喝到了茅台,西洋酒鬼第一次喝到了XO一样,怎个爽字可形容呀。’,你有没有这种感觉了?”
        “嗯,我一下子知道这里的差别主要在原来的实例化是写死在程序里的,而现在用了反射就可以利用字符串来实例化对象,而变量是可以
更换的。”小菜说道。
        “由于字符串是可以写成变量,而变量的值到底是CashReturn(返利),还是CashRebate(打折),完全可以由谁决定?”大鸟再问。
         “当然是由用户在下拉中选择的选项决定,也就是说,我只要把下拉选项的值改成这些算法子类的名称就好了,是吧?”
        “你说得对,不过还不是最好。因为把comboBox的每个选项value都改为算法子类的名称。以后我们要加子类,你不是还要去改comboBox吗?继续往下想,现在我们的代码对有谁依赖?”
        “对下拉控件comboBox的选项有依赖。”
        “那么怎么办,这个控件的选项可不可以通过别的方式生成。比如利用它的绑定?”
        “你的意思是读数据库?”
        “读数据库当然最好了,其实用不着这么麻烦,我们不是有XML这个东东吗,写个配置文件不就解决了?”
        “哦,我知道你的意思了,让它去读XML的配置文件,来生成这个下拉列表框,然后再根据用户的选择,通过反射实时的实例化出相应的算法对象,最终利用策略模式计算最终的结果。好的好的,我马上去写出来。我现在真有一种不把程序写出来就难受的感觉了。”小菜急切的说。
       “OK,还有一个小细节,你的CashRebate和CashReturn在构造函数中都是有参数的,这需要用到CreateInstance()方法的重载函数,不会用去查帮助吧!”
       “好嘞!你别走哦,等我,不见不散!”小菜向外跑着还叫道。
        大鸟摇头苦笑,嘴里嘟囔着:“这小子,忒急了吧!还不见不散呢,难道真没完没了啦!”

一个小时后,小菜交出了商场收银程序的第五份作业。

客户端主要代码:

using System.Reflection;DataSet ds;//用于存放配置文件信息double total = 0.0d;//用于总计private void Form1_Load(object sender, EventArgs e){//读配置文件ds = new DataSet();ds.ReadXml(Application.StartupPath + "\\CashAcceptType.xml");//将读取到的记录绑定到下拉列表框中foreach (DataRowView dr in ds.Tables[0].DefaultView){cbxType.Items.Add(dr["name"].ToString());}cbxType.SelectedIndex = 0;}private void btnOk_Click(object sender, EventArgs e){CashContext cc = new CashContext();//根据用户的选项,查询用户选择项的相关行DataRow dr = ((DataRow[])ds.Tables[0].Select("name='" + cbxType.SelectedItem.ToString()+"'"))[0];//声明一个参数的对象数组object[] args =null;//若有参数,则将其分割成字符串数组,用于实例化时所用的参数if (dr["para"].ToString() != "")args = dr["para"].ToString().Split(',');//通过反射实例化出相应的算法对象cc.setBehavior((CashSuper)Assembly.Load("商场管理软件").CreateInstance("商场管理软件." + dr["class"].ToString(), false, BindingFlags.Default, null, args, null, null));double totalPrices = 0d;totalPrices = cc.GetResult(Convert.ToDouble(txtPrice.Text) * Convert.ToDouble(txtNum.Text));total = total + totalPrices;lbxList.Items.Add("单价:" + txtPrice.Text + " 数量:" + txtNum.Text + " "+cbxType.SelectedItem+ " 合计:" + totalPrices.ToString());lblResult.Text = total.ToString();}

配置文件 CashAcceptType.xml 的代码

 1<?xml version="1.0" encoding="utf-8" ?>
 2<CashAcceptType>
 3    <type>
 4        <name>正常收费</name>
 5        <class>CashNormal</class>
 6        <para></para>
 7    </type>
 8    <type>
 9        <name>满300返100</name>
10        <class>CashReturn</class>
11        <para>300,100</para>
12    </type>
13    <type>
14        <name>满200返50</name>
15        <class>CashReturn</class>
16        <para>200,50</para>
17    </type>
18    <type>
19        <name>打8折</name>
20        <class>CashRebate</class>
21        <para>0.8</para>
22    </type>
23    <type>
24        <name>打7折</name>
25        <class>CashRebate</class>
26        <para>0.7</para>
27    </type>
28</CashAcceptType>

实现的界面同之前一样(可点击使用)

“大鸟,我再次搞定了,这会是真的明白了。”小菜说。
         “说说看,你现在的理解!”大鸟问。
         “无论你的需求是什么,我现在连程序都不动,只需要去改改XML文件就全部摆平。比如你如果觉得现在满300送100太多,要改成送80,我只需要去XML文件里改就行,再比如你希望增加新的算法,比如积分返点,那我先写一个返点的算法类继承CashSuper,再去改一下XML文件,对过去的代码依然不动。总之,现在是真的做到了程序易维护,可扩展。”小菜得意地坏笑道,“吼吼!此时商场老板以为要改一天的程序,我几分钟就搞定,一天都可以休息。反射——真是程序员的快乐呀!”
       “在做梦了吧,你当老板是傻瓜,会用反射才是正常水平,不会用的早应该走人了。”大鸟打击了小菜的情绪,“不过呢小菜的确是有长进,不再是小菜鸟了。那你说说看,现在代码还有没有问题。”
        “还有不足?不会吧,我都改5次了,重构到了这个地步,还会有什么问题?”小菜不以为然。
       “知足是可以常乐,但知足如何能进步!你的代码真的没有问题了,比如说,你现在把列表是打印在了listBox列表框中,我现在还需要输出到打印机打印成交易单据,我还希望这些清单能存入数据库中,你需要改客户端的代码吗?”
       “这个,你这是加需求了,更改当然是必须的。”
       “更改是必须的没有错,但为什么我只是要对交易清单加打印和存数据,就需要去改客户端的代码呢?这两者没什么关系吧?”大鸟说。
       “啊,你的意思是…………”
        “别急着下结论,先去好好思考一下再说。”大鸟打断了小菜。

(待续)
本文源代码

出处:http://www.cnblogs.com/cj723/archive/2007/03/22/683951.html

大话设计模式(九 反射——程序员的快乐!)相关推荐

  1. 『设计模式』反射,反射程序员的快乐!为什么我老是加班?为什么我工资不如他多?原来是我不懂反射!

    23种设计模式+额外常用设计模式汇总 (持续更新) Java是一门准动态语言,是因为存在反射机制,如果你不会是不是就等于白学了? 看完不会,请评论,我亲自给你解释,嘻嘻! 什么是动态语言? 动态语言, ...

  2. 反射 数据类型_c#反射,反射程序员的快乐

    1.什么是反射? 我们先来看一张图片吧. 根据树木的轮廓,我们在水中能得到,一棵一模一样的树木.好的,先带大家简单了解下,那么,再程序中是如何体现呢! 反射是.NET中的重要机制,通过反射,可以在运行 ...

  3. Unity C#基础之 反射反射,程序员的快乐

    反射反射,程序员的快乐 这句话想必大家都经常听过,基本上在绝大多数的框架和一些设计模式中都能看到反射的身影(MVC.IOC.AOP.O/RM), 反射:是.Net Framework提供的一个帮助类库 ...

  4. 程序员的快乐就是这么朴素无华且枯燥

    前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:github.com/ZhongFuChen- 我是一个程序员,外行人都以为我是修电脑的,我笑了笑,随意ctrl c+ctrl ...

  5. 设计模式大集锦 程序员面试全攻略

    一.入门级程序员的面试题: 这些软件设计和设计模式的先关问题大多会出现在初学者面试情景中,什么是设计模式?特定的设计模式又是什么?等等这些概念,也许你很轻易回答这些概念,但文内提供的这些问题也许能给你 ...

  6. html5编写微信留言,HTML5春节(支持微信和填写姓名)祝福所有程序员幸福快乐...

    [实例简介] HTML5春节(支持微信和填写姓名)祝福所有程序员幸福快乐 [实例截图] [核心代码] chunjie └── chunjie ├── cjold_m.css ├── index.htm ...

  7. 程序员的快乐往往就是这么朴素无华且枯燥!

    作者 | 程序员小吴 来源 | 五分钟学算法 前几天在头条和知乎写了个段子,居然收获了 10w+ 的阅读,今天分享给大家. 程序员的快乐往往就是这么朴素无华且枯燥! 我,打开了 LeetCode 官网 ...

  8. 九年老程序员推荐的java书籍,建议收藏!!

    首先知乎爬取了以 #java# 为关键词的三千本书,然后去除评分在7.5以下和评论人数少于150人次的书籍,最终得到以下筛选出以下结果. 我将以评论人数排行榜&评分排行榜&综合排行榜, ...

  9. 程序员如何快乐学习?

    经历了小学到大学的学习,经历了一次又一次应试学习,经历了实践操作的 学车学习,我们的一生都是在不断的学习着.........我们不断的在体会着学习这一过程,那究竟什么才是学习?又如何学习?学习是一件痛 ...

最新文章

  1. 计算机视觉分析:传统视觉VS深度学习
  2. 牛人推荐的跨浏览器兼容性总结
  3. Java简介与HelloWorld第一行代码
  4. 电脑桌面的东西突然不显示了
  5. c语言二进制转十进制(附完整源码)
  6. CharNet算法详解
  7. struts2的s:iterator 标签 详解
  8. 山东青岛市南区:创建物联网 信息化管理涉案财物
  9. P6620 [省选联考 2020 A 卷] 组合数问题(斯特林数、下降幂)
  10. Git 仓库基础操作
  11. html3d转换,CSS3 3D 转换
  12. 关于读《ajax后退解决方案(一)》笔记
  13. 洛谷P3265 装备购买
  14. [摘抄]3D电视原理
  15. 计算机用户界面英文,计算机主板CMOS界面英文翻译(2)
  16. Ubuntu 20.04 快速搭建Vue开发环境
  17. 现代互联网的TCP拥塞控制(CC)算法评谈
  18. Web开发技术课程设计
  19. 并发和并行以及线程安全
  20. 泰国旅游必拍照打卡景点推荐,高清靓图欣赏

热门文章

  1. mysql5.6 replication_MySQL5.6 Replication主从复制(读写分离) 配置完整版
  2. 实战SSM_O2O商铺_42【前端展示】店铺列表页面View层的实现
  3. php jquery 全选删除,jQuery+php简单实现全选删除的方法
  4. 【洛谷】马的遍历--广度优先搜索(BFS)
  5. java dataurl_java url参数去重
  6. led灯串怎么摆造型_如何驱动LED灯串小绝招
  7. C语言之动态内存管理与动态内存函数
  8. python 验证回文串
  9. 核磁共振波谱分析_实验室各种仪器原理动图剖析,这么多分析仪器原理,1次搞清楚了...
  10. mockito mock void方法_纯干货,浅谈Mockito在单元测试中的实际应用