现在的位置: 首页 > 综合 > 正文

大话设计模式 – 笔记

2013年06月26日 ⁄ 综合 ⁄ 共 11530字 ⁄ 字号 评论关闭

发现这本书写的确实不错,通过刚大学毕业的小菜和大鸟之间的对话模式,深入浅出地从实际问题出发,层层推进软件设计模式。文章从一个大学生笔试题讲起,也让我想起了自己的笔试经历,其实发现自己自从大学毕业之后,就没有再学习过太多的理论,做的都是实验室里的小打小闹的小软件,面对每次实验的时候,一帮研究数据的所谓物理学家,对软件或这或那的需求变化,再加上1个多月公司的实习经历,让我真切感受到设计模式的重要。发现自己还停留在ctrl+c,ctrl+v的水平,呵呵。也许一直以来所处的环境让我没有意识到这点吧,这次实习经历感觉真是收获颇多,至少知道了设计模式在软件开发、维护过程中的重要性。

        下面就结合自己看的进度,对每章每节做个小的说明,便于以后复习之用,加深记忆,呵呵。
        
目录
第1章 代码无错就是优?——简单工厂模式
1.1 面试受挫  :我还好,笔试后都给了面试机会,呵呵
1.2 初学者代码毛病:命名习惯,重复的if判断
1.3 代码规范:好的命名习惯,意外处理,switch case 代替 if
1.4 面向对象编程:碰到问题不能直觉地用计算机逻辑来描述和求解,这样只会使程序只为满足当前的需求,程序不容易维护,不容易扩张,更不容易服用,达不到高质量的代码要求
1.5 活字印刷,面向对象:曹操和印刷工匠的刻板印刷的事情,引出了活字印刷的优点(即面向对象的优点):第一只需要改要改的字,此为可维护;第二字可以重复使用,此为可复用;第三,若要加字,只需要另刻字加入即可,此为可扩展;第四,字的排列可能是竖排可能是横排,只需要将活字移动即可满足排列要求,此为灵活性好。 四大发明当中,火药,指南针,造纸术都是从无到有,从未知到发现的伟大发明,而活字印刷仅仅是从刻板印刷到活字印刷的一次技术上的进步,就是凭借其面向对象的思想而成为四大发明之一,呵呵。
1.6 面向对象的好处:软件开发几年后,经历了太多类似曹操这样的客户要改变需求,其实这些要求也不过分,就是改几个字吗,但面对已完成的代码,实在有点痛苦,原因就是原先的程序不容易维护,灵活性差,不容易扩展,更谈不上复用,因此面对需要变化,加班加点。最近在做实验,正好我也在学这本书,当需求变化的时候,之前我都是早理由推,现在我明白了这是我的责任,呵呵。 开始考虑通过封装,继承,多态把程序的耦合度降低。使程序更加灵活,容易修改,并易于复用。
1.7 复制vs.复用:初级程序员的工作就是ctrl+c,v.这是非常不好的编码习惯,当代码重复到一定程度,就难维护,所以要尽可能的办法避免重复。
1.8 业务的封装:业务逻辑与界面逻辑的分开,让耦合度降低。 实现运算类(operation),这样不单是windows程序,web版程序,pda,手机软件需要此运算都可以用它。不过这里我们才应到了封装。 继承和多态还没有体现。
1.9 紧耦合vs.松耦合:目前operation类只有加减乘除,如果需要开根运算,当然可以直接加一个switch分支,但是却需要加减乘除的运算都来参与编译,本来只是让加一个功能,却使得原有运行良好的功能代码产生变化,有点风险。因此可以考虑把加减乘除等运算分离,修改其中一个不影响另外的。定义一个基类和一些抽象的虚方法实现继承和多态。
1.10 简单工厂模式:用一个单独的类来做这个创建实例的过程,这就是工厂。只需要输入运算符号,工厂就实例化出合适的对象,通过多态,返回父类的方式实现了计算器的结果。当我们需要改加法运算的时候,只需要改operationAdd,当需要添加各种复杂运算的时候,只需要添加相应的运算子类即可,另外再修改运算类工厂,加switch分支。修改界面也跟运算没关系。
1.11 UML类图:类图分三层,第一层是类的名称,如果是抽象类,则用斜体表示。第二层是类的特性,通常是字段和属性。第三层是类的操作,通常是方法和行为。注意前面的符号+public,-private,#protected。 接口图与类图的区别是顶端有interface显示,第一行是接口名称,第二行是接口方法。接口还有一种表示方法就是棒棒糖表示法。继承关系用空心三角形+实线表示。实现接口用空心三角形+虚线表示。企鹅与气候有很大的关联,即企鹅需要知道气候的变化,需要了解气候的规律,这种关系叫关联,关联用实线箭头来表示。大雁和雁群是一种聚合关系,他是一种弱拥有关系。A对象可以包含B对象,但B对象不是A对象的一部分,用空心菱形+实线箭头表示。合成(组合)是一种强的拥有关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样,合成关系用实心菱形+实线箭头表示。如果一个类可能有无数个实例,则用n来表示。关联关系、聚合关系也可以有基数。动物依赖于氧气和水,他们之间是依赖关系,用虚线箭头来表示。
编程是一门技术,更加是一门艺术~~
第2章 商场促销——策略模式
2.1 商场收银软件
2.2 增加打折
2.3 简单工厂实现:打折基本都一样,只要有个初始化参数就可以。满几送几,需要两个参数。面向对象的编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类。所以打折算法应该是一个类。现金收费抽象类,正常收费子类,打折收费子类,返利收费子类,现金收费工厂类。
      如上是简单工厂模式的灵活运用,简单工厂模式只是解决对象的创建问题,而且工厂本身包括所有的收费方式,商场是可能经常性地更改打折额度和返利额度,每次维护或扩展收费方式都要改动这个厂,以致代码需要重新编译部署,这真是糟糕的处理方式,面对算法的时常变动,应有有更好的方法。
2.4 策略模式:策略模式定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。商场收银是如何促销,用打折还是返利,其实都是一些算法,用工厂来生成算法对象,这没有错,但算法本身只是一种策略,最重要的是这些算法是随时都可能互相替换的,这就是变化点,而封装变化点是面向对象的一种很重要的思维方式。策略模式的结构图和基本代码:策略类Strategy定义所有支持的算法的公共接口,ConcreateStrategyA,B,C封装了具体的算法或行为,Context上下文,用一个Constrategy来配置,维护一个对Strategy对象的引用。
2.5 策略模式实现:之前的CashSuper就是抽象策略,而正常收费CashNormal,打折收费CashRebate和返利收费CashReturn就是三个具体策略,也就是策略模式中说的具体算法,因此可以模仿策略模式的基本代码,进行程序的修改。其实原来的4个类都不需要改了,只要加一个CashText类,并改一下客户端就行了。让具体算法与客户进行了隔离。单是感觉这样子做又回到了原来的老路了,在客户端判断使用哪一个算法了,如何将这个判断过程从客户端程序转移走呢,即将简单工厂和策略模式相结合。
2.6 策略与简单工厂结合:将实例化具体策略的过程由客户端转移到Context类中,简单工厂的应用。
简单工厂模式的用法
CashSuper csuper=CashFactory.createCashAccept(cbxType.SelectedItem.ToString());
...=csuper.GetResult(...)
策略模式与简单工厂结合的用法:
CashContext csuper=new CashContext(cbxType.SelectedItem.ToString());
...=csuper.GetResult(...);
简单工厂模式需要让客户端认识两个类,CashSuper和CashFactory,而策略模式与简单工厂模式的结合,客户端只需要认识一个类CashContext即可,耦合更加降低。调用的是CashContext的方法GetResult,这使得具体的收费算法彻底地与客户端分离,连算法的父类CashSuper都不让客户端认识了。
2.7 策略模式解析:策略模式是一种定义了一系列算法的方法,从概念上看,所有这些算法完成的是相同的工作,只是实现不同,他可以用相同的方式调用所有的算法,减少了各种算法类和使用算法类之间的耦合。策略模式的类层次为Context定义了一系列的可供重用的算法或行为。继承有助于析取出这些算法的公共功能。对于各种打折返利或者其他算法,他们公共的功能就是或者计算费用的结果GetResult,这使得算法间有了抽象的父类CashSuper,这种策略模式的优点就是简化了单元测试,因为每个算法都有自己的类,可以通过通过自己的接口单独测试。
在客户端代码中就消除了条件语句,避免了大量的判断。策略模式就是用来封装算法的,但在实践中,我们发现可以用他封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。
但是在基本的策略模式中,选择所用的具体实现的职责由客户端对象承担,并转给策略模式的Context对象,这本身并没有解除客户端需要选择判断的压力,而策略模式与简单工厂模式相结合后,选择具体实现的职责也可以由Context来承担,这就最大化地减轻了客户端的职责。
  但是因为在CashContext里还是利用了switch,也就是需要增加一个算法的时候,还的修改switch代码,总还是让人不爽,因此一种更好的反射技术可以解决此问题,反射反射,程序员的快乐,呵呵。抽象工厂模式章节中讲解反射。
第3章 拍摄UFO——单一职责原则
3.1 新手机
3.2 拍摄
3.3 没用的东西
3.4 单一职责原则:就一个类而言,应该仅有一个引起它变化的原因。
3.5 方块游戏的设计:如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这些耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。
    软件设计真正要做的许多内容,就是发现职责并把那些职责互相分离,如果能想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责。
3.6 手机职责过多吗?
第4章 考研求职两不误——开放-封闭原则
4.1 考研失败:一国两制。在软件设计模式中,这种不能修改,但可以扩展的思想也是最重要的一种设计原则,它就是开放-封闭原则(The Open-Closed Principle OCP)或叫开-闭原则。
4.2 开放-封闭原则:是说软件实体(类,模块,函数等等)应该可以扩展,但是不可修改。两个特性,对于扩展是开放的,对于更改是封闭的。怎样的设计才能面对需求的改变却可以保持相对稳定,从而使得习题可以在第一个版本以后不断推出新的版本呢?开放-封闭给了我们答案。即多扩展少修改。
4.3 何时应对变化:开放-封闭原则的意思就是说:设计的时候,时刻要考虑,尽量让这个类是足够好,写好了就不要去修改,如果新需求来,我们添加一些类就完事了,原来的代码能不动则不动。
     无论模块是多么的封闭,都会存在一些无法对之封闭的变化。既然不可能完全封闭,设计人员必须对于他设计的模块应该对哪种变化封闭作出选择。他必须先猜测出最有可能发生的变化种类,然后构造抽象来隔离那些变化。在我们最初编写代码时,假设变化不会发生,当变化发生时,我们就创建抽象来隔离以后发生的同类变化。 开-闭原则的精神在于:面对需求,对程序的改动是通过增加新代码进行的,而不是更改现有的代码。
 我们希望的是在开发工作展开不久就知道可能发生的变化。查明可能发生的变化所等待的时间越长,要创建正确的抽象就越困难。
开放-封闭原则是面向对象设计的核心所在。遵循这个原则可以带来面向对象技术所声称的巨大好处,也就是可维护、可扩展、可复用、灵活性好。开发人员应该仅对程序中呈现出频繁变化的那些部分做出抽象,然而对于应用程序中的每个部分都刻意地进行抽象同样不是一个好主意。拒绝不成熟的抽象和抽象本身一样重要。
4.4 两手准备,并全力以赴
第5章 会修电脑不会修收音机?——依赖倒转原则
5.1 MM请求修电脑
5.2 电话遥控修电脑
5.3 依赖倒转原则:原话解释是抽象不应该依赖细节,细节应该依赖于抽象。说白了,就是要针对接口编程,不要对实现编程。 高层模块不应该依赖底层模块,两个都应该依赖抽象。
5.4 里氏代换原则:一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别。也就是说,在软件里面,把父类都替换成它的子类,程序的行为没有变化。简单地说,子类必须能够替换掉他们的父类型。 只有当子类可以替换掉父类,软件单位的功能不受到影响时,父类才真正被复用,而子类也能够在父类的基础上增加新的行为。 正是由于子类型的可替换性才使得使用父类类型的模块在无需修改的情况下就可以扩展。
程序中所有的依赖关系都是终止于抽象类或者接口,那就是面向对象的设计,反之就是过程化的设计了。
5.5 修收音机
第6章 穿什么有这么重要?——装饰模式
6.1 穿什么有这么重要?
6.2 小菜扮靓第一版
6.3 小菜扮靓第二版
6.4 装饰模式:需要把所需的功能按正确的顺序串联起来进行控制。 装饰模式,动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
装饰模式是利用SetComponent来对对象进行包装的,这样每个装饰对象的实现就和如何使用这个对象分离开了,每个装饰只关心自己的功能,不需关心如何被添加到对象链当中。
6.5 小菜扮靓第三版
6.6 装饰模式总结:装饰模式是为已有功能动态地添加更多功能的一种方式。在起初的设计中,当习题需要新功能的时候,是向旧的类中添加新的代码,这些新加的代码通常装饰了原有类的核心职责或主要行为。但这样做的问题在于,他们在主类中加入了新的字段,新的方法和新的逻辑,从而增加了主类的复杂度,而这些新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为的需要。而装饰模式却提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此,当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地,按顺序地使用装饰功能包装对象了。装饰模式的优点就是把类中的装饰功能从类中搬移去除,这样可以简化原有的类。有效地把类的核心职责和装饰功能区分开了。而已可以去除相关类中重复的装饰逻辑。
第7章 为别人做嫁衣——代理模式
7.1 为别人做嫁衣!
7.2 没有代理的代码
7.3 只有代理的代码
7.4 符合实际的代码
7.5 代理模式:为其他对象提供一种代理以控制对这个对象的访问。
7.6 代理模式应用:第一远程代理,也就是为一个对象在不同的地址空间提供局部代表。这样可以引出一个对象存在于不同地址空间的事实。例如WebService在.NET中的应用。
第二虚拟代理,是根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象。例如一个很大的HTML网页,里面有很多的文字和图片,图片是一张一张地下载后才能看到,那些未打开的图片框就是通过虚拟代理来替代了真实的图片,此时代理存储了真实图片的路径和尺寸。即浏览器用代理模式来优化下载。
第三是安全代理,用来控制真实对象访问时的权限,一般用于对象应该有不同的访问权限的时候。
第四是智能指引,是指当调用真实的对象时,代理处理另外一些事。例如计算真实对象的引用次数,这样当该对象没有引用时,可以自动释放它;或当第一次引用一个持久对象时,将它装入内存;或者在访问一个实际对象前,检查是否已经锁定它,以确保其他对象不能改变它。他们都是通过代理在访问一个对象时附加一些内务处理。
代理模式其实就是在访问对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。
7.7 秀才让小六代其求婚
第8章 雷锋依然在人间——工厂方法模式
8.1 再现活雷锋
8.2 简单工厂模式实现
8.3 工厂方法模式实现
8.4 简单工厂vs.工厂方法: 简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。但是对于简单工厂模式,如果要加一个运算功能,就需要给运算工厂类的方法里加case分支条件,修改原有的类,这可是不是好方法,这等于说,我们不但对扩展开放了,对修改也开放了,这样就违背了开放-封闭原则,于是工厂方法就来了。工厂方法模式(Factory Method)定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类。 这样如果要添加新的运算,就不需要更改原有的工厂类了,只需要添加此功能的运算类和相应的工厂类就可以了,这样整个工厂和产品体系其实都没有修改的变化,而只是扩展的变化,这就完全符合了开放-封闭原则的精神。
工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现运算类,选择判断的问题还是存在,也就是说,工厂方法把简单工厂的内部逻辑判断移动了客户端代码来进行,你想要加功能,本来是改工厂类的,而现在是修改客户端。所以应该还有更好的方法,那就是利用反射来解决。
8.5 雷锋工厂: 工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点。
第9章 简历复印——原型模式
9.1 夸张的简历
9.2 简历代码初步实现
9.3 原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。
   对于.NET而言,那个原型抽象类Prototype是用不着的,因为克隆实在是太常用了,所以.NET在System命名空间中提供了ICloneable接口,其中就是唯一的一个方法Clone(),这样就只需要实现这个接口就可以完成原型模式了。
   一般在初始化的信息不发生变化的情况下,克隆是最好的方法,这既隐藏了对象创建的细节,又对性能是大大的提高。
9.4 简历的原型实现
9.5 浅复制与深复制:MemberwiseClone()方法是这样,如果字段是值类型的,则对该字段执行逐位复制,如果字段是引用类型,则复制引用但不复制引用的对象,因此,原始对象及其复本引用同一个对象。也就是说,如果简历类中有对象的引用,那么引用的对象数据是不会不饿克隆过来的。
浅复制,浅复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。但我们可能更需要这样的一种需求,把要复制的对象所引用的对象都复制一遍。深复制把引用对象的变量指向复制过的新对象,而不是原来的被引用的对象。
9.6 简历的深复制实现
9.7 复制简历vs.手写求职信
第10章 考题抄错会做也白搭——模板方法模式
10.1 选择题不会做,蒙呗!
10.2 重复=易错+难改
10.3 提炼代码: 既然用了继承,并且肯定这个继承有意义,就应该要成为子类的模板,所有重复的代码都应该要上升到父类去,而不是让每个子类都去重复。哈,模板方法登场了,当我们要完成在某一个细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模板方法模式来处理。
10.4 模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤.
AbstractClass是抽象类,其实也就是一抽象模板,定义并实现了一个模板方法.这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现.顶级逻辑也有可能调用一些具体方法.
10.5 模板方法模式特点: 模板方法模式是通过把不变行为搬移到超类,去除子类中的重复代码来体现它的优势. 模板方法模式就是提供了一个很好的代码复用平台. 当我们遇到右一系列步骤构成的过程需要执行,这个过程从高层次上看是相同的,但有些步骤的实现可能不同,这个时候,我们通常就应该要考虑用模板方法模式.
10.6 主观题,看你怎么蒙
第11章 无熟人难办事?——迪米特法则
11.1 第一天上班
11.2 无熟人难办事
11.3 迪米特法则:也叫最少知识原则。如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
 迪米特法则首先强调的前提是在类的结构设计上,每一个类应当尽量降低成员的访问限制,也就是,一个类包装好自己的private状态,不需要让别的类知道的字段或者行为就不要公开。迪米特法则其根本思想,是强调了类之间的松耦合。
类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成波及。
第12章 牛市股票还会亏钱?——外观模式
12.1 牛市股票还会亏钱?
12.2 股民炒股代码
12.3 投资基金代码
12.4 外观模式:为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
12.5 何时使用外观模式:外观模式完美地体现了依赖倒转原则和迪米特法则的思想。
外观模式的使用分三个阶段:首先,在设计初期阶段,应该要有意识的将不同的两个层分离,比如经典的三层架构,就需要考虑在数据访问层和业务逻辑层,业务逻辑层和表示层的层与层之间建立外观Facade,这样可以为复杂的子系统提供一个简单的接口,使得耦合大大降低。其次,在开发阶段,子系统往往因为不断的重构演化而变得越来越复杂,大多数的模式使用时也都会产生很多很小的类,这本是好事,但也给外部调用他们的用户程序带来了使用上的困难,增加外观Facade,可以提供一个简单的接口,减少他们之间的依赖。第三,在维护一个遗留的大型系统时,可能这个系统已经非常难以维护和扩展了,但因为他包含非常重要的功能,新的需求开发必须依赖于它,此时用外观模式Facade也是非常合适的。你可以为新系统开发一个外观Facade类,来提供设计粗糙或高度复杂的遗留代码的比较清晰简单的接口,让新系统与Facade对象交互,Facade与遗留代码交互所有复杂的工作。
第13章 好菜每回味不同——建造者模式
13.1 炒面没放盐
依赖倒转原则,抽象不应该依赖细节,细节应该依赖于抽象,由于我们要吃的菜都依赖于厨师这样的细节,所以我们就很被动。
13.2 建造小人一
13.3 建造小人二
13.4 建造者模式:如果我们需要将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示意图时,我们需要应用一个设计模式,“建造者Builder模式”,又叫生成器模式。建造者模式可以将一个产品的内部表象与产品的生产过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。如果我们用了建造者模式,那么用户就只需指定需要建造的类型就可以得到它们,而具体建造过程和细节就不需知道了。
建造者模式,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
13.5 建造者模式解析
13.6 建造者模式基本代码:
 建造者模式是在当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时适用的模式。
第14章 老板回来,我不知道——观察者模式
14.1 老板回来?我不知道!
14.2 双向耦合的代码
14.3 解耦实践一
14.4 解耦实践二
14.5 观察者模式:又叫发布-订阅模式,定义了一种一对多的依赖关系,让多种观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
14.6 观察者模式特点:将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维护一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。而观察者模式的关键对象是主题Subject和观察者Observer,一个Subject可以有任意数目的依赖它的Observer,一旦Subject的状态发生改变,所有Observer都可以得到通知。Subject发出通知时并不需要知道谁是他的观察者,也就是说,具体观察者是谁,他根本不需要知道,而任何一个具体观察者不知道也不需要知道其他观察者的存在。
当一个对象的改变需要同时改变其他对象的时候,而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式。当一个抽象模型有两个方面,其中一个方面依赖于另一方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。总之,观察者模式所做的工作其实就是在接触耦合,让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。
14.7 观察者模式的不足
14.8 事件委托实现
14.9 事件委托说明:委托就是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看作是对函数的抽象,是函数的“类”,委托的实例将代表一个具体的函数。
一旦为委托分配了方法,委托将与该方法具有完全相同的行为。而且,一个委托可以搭载多个方法,所有方法被依次唤起,更重要的是,它可以使得委托对象所搭载的方法并不需要属于同一个类。委托也是有前提的,那就是委托对象所搭载的所有方法必须具有相同的原形和形式,也就是拥有相同的参数列表和返回值类型。
14.10 石守吉失手机后的委托
第15章 就不能不换DB吗?——抽象工厂模式
15.1 就不能不换DB吗?
15.2 最基本的数据访问程序
15.3 用了工厂方法模式的数据访问程序:
工厂方法模式是定义一个用于创建对象的接口,让子类决定实例化哪一个类。
15.4 用了抽象工厂模式的数据访问程序:
只有一个User类和User操作类的时候,是只需要工厂方法模式的,但现在显然数据库中有很多的表,而Sql Server与Access又是两大不同的分类,所以解决这种涉及到多个产品系列的问题,有一个专门的工厂模式叫抽象工厂模式。
15.5 抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
15.6 抽象工厂模式的优点与缺点:
最大的好处便是易于交换产品系列,由于具体工厂类,在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。我们的设计不能去防止需求的更改,那么我们的理想便是让改动变得最小,现在如果你要更改数据库访问,我们只需要更改具体工厂就可以做到。第二大好处是,它让具体的创建实例过程与客户端分离,客户端是通过他们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。
是个模式都是会有缺点的,都有不适用的时候,要辩证地看待问题,抽象工厂模式可以很方便地切换两个数据访问的代码,但是如果我们的需求来自增加功能,比如要添加项目表,就至少增加三个类,IProject,SqlserverProject,AccessProject,还需要修改IFactory,SqlserverFactory,AccessFactory才可以完全实现。另外我们的客户端程序类显然不会只有一个,有很多地方都在使用IUser或IDepartment,而这样的设计,其实在每一个类的开始都需要声明IFactory factory=new SqlserverFactory(),如果我们有100个调用数据库访问的类,是不是要更改100次这样的代码。编程是门艺术,这样大批量的改动,显然是非常丑陋的做法。
15.7 用简单工厂来改进抽象工厂:
去除IFactory,SqlserverFactory,AccessFactory三个工厂类,取而代之的是DataAccess类,用一个简单工厂模式来实现。
15.8 用反射+抽象工厂的数据访问程序
依赖注入(Dependency Injection)可以解决switch问题。本来依赖注入是需要专门的IoC容器提供,比如Spring.NET,显然当前这个程序不需要这么麻烦,只需要了解一个简单的.NET技术“反射”就可以了。
反射技术的使用格式:Assembly.Load("程序集名称").CreateInstance("命名空间.类名称")。 在程序顶端写上 using System.Reflection;来引用Reflection,就可以使用反射来帮我么克服抽象工厂模式的先天不足了。
常规的写法:
IUser result=new SqlserverUser();

抱歉!评论已关闭.