戏说面向对象程序设计(C#版) 第九章 反射——程序员的快乐!

第九章    反射——程序员的快乐! 织梦内容管理系统

 

本文来自织梦

         “到底如何去改良策略模式呢?”小菜恳切地问道。

织梦好,好织梦

          “你仔细观察过没有,你的代码,不管是用工厂模式写的,还是用策略模式写的,那个分支的switch依然去不掉。

本文来自织梦

原因在哪里?”大鸟反问道。 内容来自dedecms

          “因为程序里有下拉选择,用户是有选择的,那么程序就必须要根据用户的选择来决定实例化哪一个子类对象。无 本文来自织梦

论是在客户端窗体类编程还是到工厂类里编程,这个switch总是少不掉的。问题主要出在这里。”小菜十分肯定的说。

copyright dedecms

          “是呀,”大鸟道,“所以我们要考虑的就是可不可以不在程序里写明‘如果是打折就去实例化CashRebate类,如果是

织梦好,好织梦

返利就去实例化CashReturn类’这样的语句,而是在当用户做了下拉选择后,再根据用户的选择去某个地方找应该要实例

本文来自织梦

化的类是哪一个。这样,我们的switch就可以对它说再见了。”

内容来自dedecms

        “听不太懂哦,什么叫‘去某个地方找应该要实例化的类是哪一个’?’小菜糊涂地说       。

内容来自dedecms

        “ ,我要说的就是一种编程方式:依赖注入(Dependency Injection),从字面上不太好理解,我们也不去管它。 copyright dedecms

关键在于如何去用这种方法来解决我们的switch问题。本来依赖注入是需要专门的IoC容器提供,比如spring.net,显然 dedecms.com

当前这个程序不需要这么麻烦,你只需要再了解一个简单的.net技术‘反射’就可以了。”

织梦好,好织梦

        “大鸟,你一下子说出又是‘依赖注入’又是‘反射’这些莫名其妙的名词,我有点晕哦!”小菜有些犯困,“我就想知道,

内容来自dedecms

如何向switch说bye-bye!至于那些什么概念我不想了解。” 内容来自dedecms

        “心急讨不了好媳妇!你急什么?”大鸟     嘲笑道,“反射技术看起来很玄乎,其实实际用起来不算难。”

内容来自dedecms

        “请看下面的两个样例: 本文来自织梦

1   //实例化方法一 内容来自dedecms

2   //原来我们把一个类实例化是这样的

织梦内容管理系统

3   Animal animal=newCat();  //声明一个动物对象,名称叫animal,然后将animal实例化成猫类的对象 织梦内容管理系统

4

织梦好,好织梦

5   //实例化方法二 本文来自织梦

6   //我们还可以用反射的办法得到这个实例 织梦内容管理系统

7   usingSystem.Reflection;//先引用System.Reflection

织梦好,好织梦

8   //假设当前程序集是AnimalSystem,名称空间也是AnimalSystem dedecms.com

9   Animal animal = (Animal)Assembly.Load("AnimalSystem").CreateInstance("AnimalSystem.Cat");

dedecms.com

  织梦好,好织梦

其中关键是

dedecms.com

Assembly.Load("程序集名称").CreateInstance("名称空间.类名称") 织梦内容管理系统

那也就是说,我们可以在实例化的时候,再给计算机一个类的名称字符串,来让计算机知道应该实例化哪一个类。”大鸟 copyright dedecms

讲解道。

织梦好,好织梦

        “你的意思是,我之前写的‘cc.setBehavior(new CashNormal());’可以改写为

织梦好,好织梦

‘cc.setBehavior((CashSuper)Assembly.Load("商场管理软件").CreateInstance("商场管理软件.CashNormal")’,不过,这

织梦内容管理系统

只不过是换了种写法而已,又有什么神奇之处呢?”小菜依然迷茫。 本文来自织梦

        “分析一下,原来new CashNormal()是什么?是否是写死在程序里的代码,你可以灵活更换吗?”大鸟问。 本文来自织梦

        “不可以,那还换什么,写什么就是什么了呗。” 织梦好,好织梦

        “那你说,在反射中的CreateInstance("商场管理软件.CashNormal"),可以灵活更换‘CashNormal’吗?”大鸟接着问。 本文来自织梦

        “还不是一样,写死在代码…………等等,哦!!!我明白了。”小菜一下子顿悟过来, 织梦内容管理系统

起来。“因为这里是字符串,可以用变量来处理,也就可以根据需要更换。哦,My God!太妙了!”

内容来自dedecms

,兴奋 dedecms.com

       “ 哈哈,博客园中的有篇博文《四大发明之活字印刷——面向对象思想的胜利》中曾经写过,‘体会到面向对象带

copyright dedecms

来的好处,那种感觉应该就如同是一中国酒鬼第一次喝到了茅台,西洋酒鬼第一次喝到了XO一样,怎个爽字可形容呀。’, copyright dedecms

你有没有这种感觉了?”

内容来自dedecms

        “嗯,我一下子知道这里的差别主要在原来的实例化是写死在程序里的,而现在用了反射就可以利用字符串来实例 dedecms.com

化对象,而变量是可以 copyright dedecms

更换的。”小菜说道。

内容来自dedecms

        “由于字符串是可以写成变量,而变量的值到底是CashReturn(返利),还是CashRebate(打折),完全可以由 织梦内容管理系统

谁决定?”大鸟再问。 copyright dedecms

          “当然是由用户在下拉中选择的选项决定,也就是说,我只要把下拉选项的值改成这些算法子类的名称就好了,是

copyright dedecms

吧?”

内容来自dedecms

        “你说得对,不过还不是最好。因为把comboBox的每个选项value都改为算法子类的名称。以后我们要加子类,你

内容来自dedecms

不是还要去改comboBox吗?继续往下想,现在我们的代码对有谁依赖?”

织梦好,好织梦

        “对下拉控件comboBox的选项有依赖。” 内容来自dedecms

        “那么怎么办,这个控件的选项可不可以通过别的方式生成。比如利用它的绑定?”

copyright dedecms

        “你的意思是读数据库?” 织梦内容管理系统

        “读数据库当然最好了,其实用不着这么麻烦,我们不是有XML这个东东吗,写个配置文件不就解决了?”

copyright dedecms

        “哦,我知道你的意思了,让它去读XML的配置文件,来生成这个下拉列表框,然后再根据用户的选择,通过反射 织梦内容管理系统

实时的实例化出相应的算法对象,最终利用策略模式计算最终的结果。好的好的,我马上去写出来。我现在真有一种不

内容来自dedecms

把程序写出来就难受的感觉了。”小菜急切的说。 内容来自dedecms

        “OK,还有一个小细节,你的CashRebate和CashReturn在构造函数中都是有参数的,这需要用到CreateInstance() dedecms.com

方法的重载函数,不会用去查帮助吧!”

织梦好,好织梦

        “好嘞!你别走哦,等我,不见不散!”小菜向外跑着还叫道。

copyright dedecms

大鸟摇头苦笑,嘴里嘟囔着:“这小子,忒急了吧!还不见不散呢,难道真没完没了啦!” copyright dedecms

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

 

内容来自dedecms

客户端主要代码: copyright dedecms

  copyright dedecms

usingSystem.Reflection;

copyright dedecms

DataSetds;//用于存放配置文件信息

织梦好,好织梦

doubletotal = 0.0d;//用于总计

copyright dedecms

 

本文来自织梦

private    voidForm1_Load(objectsender,    EventArgse) 内容来自dedecms

{

本文来自织梦

//读配置文件 织梦好,好织梦

    ds =   new         DataSet(); dedecms.com

    ds.ReadXml(Application.StartupPath +     "\\CashAcceptType.xml");

织梦好,好织梦

//将读取到的记录绑定到下拉列表框中 dedecms.com

foreach(DataRowViewdr  inds.Tables[0].DefaultView)

dedecms.com

    {

dedecms.com

        cbxType.Items.Add(dr["name"].ToString()); copyright dedecms

    } 织梦内容管理系统

    cbxType.SelectedIndex = 0; 本文来自织梦

} 织梦好,好织梦

  本文来自织梦

private    voidbtnOk_Click(objectsender,       EventArgse)

本文来自织梦

{ 织梦内容管理系统

    CashContext cc =  newCashContext();

织梦内容管理系统

//根据用户的选项,查询用户选择项的相关行

copyright dedecms

DataRowdr = ((DataRow[])ds.Tables[0].Select

dedecms.com

        ("name='"+ cbxType.SelectedItem.ToString() +         "'")

织梦好,好织梦

        )[0];

dedecms.com

//声明一个参数的对象数组 织梦好,好织梦

object[] args =       null;

dedecms.com

//若有参数,则将其分割成字符串数组,用于实例化时所用的参数 内容来自dedecms

if(dr["para"].ToString() !=              "")

内容来自dedecms

        args = dr["para"].ToString().Split(',');

织梦内容管理系统

//通过反射实例化出相应的算法对象 织梦好,好织梦

  本文来自织梦

    cc.setBehavior( copyright dedecms

        (CashSuper)Assembly.Load("商场管理软件").CreateInstance( copyright dedecms

"商场管理软件."+ dr["class"].ToString(),              false,  dedecms.com

            BindingFlags.Default,     null, args,      null,    null dedecms.com

        )); 织梦内容管理系统

 

内容来自dedecms

doubletotalPrices = 0d; 本文来自织梦

    totalPrices = cc.GetResult(Convert.ToDouble(txtPrice.Text) * 织梦好,好织梦

Convert.ToDouble(txtNum.Text));

内容来自dedecms

    total = total + totalPrices; 织梦内容管理系统

    lbxList.Items.Add( copyright dedecms

"单价:"+ txtPrice.Text +  织梦好,好织梦

" 数量:"+ txtNum.Text +         " "+ cbxType.SelectedItem + 

dedecms.com

" 合计:"+ totalPrices.ToString());

copyright dedecms

    lblResult.Text = total.ToString();

织梦内容管理系统

} 内容来自dedecms

配置文件CashAcceptType.xml   的代码 copyright dedecms

<?xml version="1.0"    encoding="utf-8"?> copyright dedecms

<CashAcceptType> 织梦内容管理系统

  <type>

本文来自织梦

    <name>正常收费</name> dedecms.com

    <class>CashNormal</class> dedecms.com

    <para></para>

本文来自织梦

  </type> 内容来自dedecms

  <type>

内容来自dedecms

    <name>满300返100</name>

本文来自织梦

    <class>CashReturn</class> 本文来自织梦

    <para>300,100</para>

copyright dedecms

  </type>

dedecms.com

  <type>

copyright dedecms

    <name>满200返50</name> 本文来自织梦

    <class>CashReturn</class>

copyright dedecms

    <para>200,50</para>

copyright dedecms

  </type>

copyright dedecms

  <type>

织梦内容管理系统

    <name>打8折</name>

copyright dedecms

    <class>CashRebate</class> 本文来自织梦

    <para>0.8</para> 织梦好,好织梦

  </type>

内容来自dedecms

  <type> 织梦好,好织梦

    <name>打7折</name>

织梦好,好织梦

    <class>CashRebate</class> 织梦内容管理系统

    <para>0.7</para> dedecms.com

  </type>

织梦好,好织梦

</CashAcceptType>

内容来自dedecms

  本文来自织梦

          “大鸟,我再次搞定了,这会是真的明白了。”小菜说。

织梦内容管理系统

         “说说看,你现在的理解!”大鸟问。 织梦内容管理系统

          “无论你的需求是什么,我现在连程序都不动,只需要去改改XML 文件就全部摆平。比如你如果觉得现在满300 dedecms.com

送100 太多,要改成送80,我只需要去XML 文件里改就行,再比如你希望增加新的算法,比如积分返点,那我先写一 本文来自织梦

个返点的算法类继承CashSuper,再去改一下XML 文件,对过去的代码依然不动。总之,现在是真的做到了程序易维

copyright dedecms

护,可扩展。”        小菜得意地坏笑道,“吼吼!此时商场老板以为要改一天的程序,我几分钟就搞定,一天都可以休息。 copyright dedecms

反射——真是程序员的快乐呀!”

内容来自dedecms

        “在做梦了吧,你当老板是傻瓜,会用反射才是正常水平,不会用的早应该走人了。”大鸟打击了小菜的情绪,“不过

本文来自织梦

呢小菜的确是有长进,不再是小菜鸟了。那你说说看,现在代码还有没有问题。”

织梦好,好织梦

        “还有不足?不会吧,我都改5 次了,重构到了这个地步,还会有什么问题?”小菜不以为然。 dedecms.com

        “知足是可以常乐,但知足如何能进步!你的代码真的没有问题了,比如说,你现在把列表是打印在了listBox 列表 dedecms.com

框中,我现在还需要输出到打印机打印成交易单据,我还希望这些清单能存入数据库中,你需要改客户端的代码吗?” 织梦好,好织梦

        “这个,你这是加需求了,更改当然是必须的。”

copyright dedecms

        “更改是必须的没有错,但为什么我只是要对交易清单加打印和存数据,就需要去改客户端的代码呢?这两者没什么 内容来自dedecms

关系吧?”大鸟说。 dedecms.com

        “啊,你的意思是…………” 内容来自dedecms

        “别急着下结论,先去好好思考一下再说。”大鸟打断了小菜。

织梦好,好织梦

本文源代码CashAcceptSystem3.rar 本文来自织梦

精彩推荐
热点内容
最近更新