版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
设计原则与设计模式设计模式式的思想想根源是是基本原原则的宏宏观运用用,本质上是是没有任任何模式式的发现模式式的人永永远是大大师,而死守模模式的人人,最多只能能是一个个工匠.2设计模式式DesignPattern设计模式式DesignPattern面向对象象研究的的新领域域20世纪90年代,面面向对象象方法与与技术在在国内软软件业界界十分火火爆,人人们热衷衷于谈论论“对象象”并引引以为荣荣。十多多年来,,人们发发表、出出版了无无数的文文章和书书籍。现现在,该该写的似似乎都写写完了,,没有新新花样玩玩了,真真是一片片无聊设计模式式(DesignPattern))及时问世世,面向向对象爱爱好者们们终于有有了新的的追求3设计模式式:起源源起源ChristopherAlexander当代著名名建筑大大师加州大学学伯克利利分校建建筑学教教授、环环境结构构研究所所所长、、美国艺艺术与科科学院院院士在建筑、、室内、、计算机机、家具具设计甚甚至哲学学方面都都卓有建建树著作:《APatternLanguage》、《TheTimelessWayofBuilding》4设计模式式:起源源Gof((GangOfFour,“四人人帮”)ErichGamma,RichardHelm,RalphJohnson,JohnVlissides1995年出版了了《DesignPatterns:ElementsofReusableObject--OrientedSoftware》》该书确立立了设计计模式这这个术语语,创导导了一种种新的面面向对象象设计思思潮。从从此,参参与设计计模式研研究的人人数爆炸炸性地增增长5设计模式式:起源源6设计模式式什么叫模模式?“每一个个模式描描述了在在我们周周围不断断重复发发生的问问题,以以及该问问题的解解决方案案的核心心。这样样,你就就能一次次又一次次地使用用该解决决方案而而不必重重复劳动动”尽管软件件技术发发展非常常快,但但是仍然然有非常常多的设设计模式式可以让让我们套套用设计模式式可以帮帮助人们们简便地地复用以以前成功功的设计计方案,,提高工工作效率率7设计模式式:研究究现状设计模式式的研究究现状pattern与Java、C#pattern与组件件技术(如CORBA)pattern与系统统结构pattern与泛型型编程(genericprogramming)相结合其他(例如UML等)8模式的分分类(gof提出的23个)9创建型结构型行为型类FactoryMethodAdapter(类)InterpreterTemplateMethod
对象AbstractFactoryBuilderPrototypeSingletonAdapter(对象)BridgeCompositeDecoratorFacadeFlyweightProxyChainofResponsibilityCommandIteratorMediatorMementoObserverStateStrategyVisitorBridge((桥梁)模式案例有一个叫叫做HuntBird的游戏,,里面需需要表示示各种各各样的鸟鸟类10Bridge((桥梁)模式最初的设设计11Bridge((桥梁)模式需求变化化:鸟类类要会飞飞12Bridge((桥梁)模式如果增加加一种鸟鸟类“企企鹅”呢呢?13Bridge((桥梁)模式改进方法法:对““飞”使使用多态态14Bridge((桥梁)模式改进方法法:再次次使用继继承15Bridge((桥梁)模式如果增加加“游泳泳”行为为呢?16Bridge((桥梁)模式继承只会会使得问问题越来来越复杂杂继承是面面向对象象的基本本法宝啊啊??OO=类+对象象+继承承+消息息通信17设计原则1:组合优先优先使用组合,而不是继承设计原则则:组合合优先继承复用用的优点点可以很容容易的修修改或扩扩展父类类的实现现18设计原则则:组合合优先继承复用用的缺点点继承破坏坏封装,,因为父父类的实实现细节节完全暴暴露给子子类(白盒复用用)父类的实实现发生生改变,,则子类类必受牵牵连继承是静静态的,,不能在在运行时时发生改改变,不不灵活19设计原则则:组合合优先组合复用用的优点点不破坏封封装,这这种复用用是黑盒盒复用,,因为成成员对象象的内部部细节对对新对象象保密所需依赖赖少(只依赖接接口)是动态的的,可以以把成员员对象动动态替换换为另一一个类型型相同的的对象组合复用用的缺点点对象数量量会增加加使用委托托(delegation)会使得系系统复杂杂20设计原则则:组合合优先组合优先先Favorcompositionoverinheritance当需要应应对变化化的时候候,应该该首先使使用组合合的方式式,而不不是继承承因为组合合更加灵灵活例1:汽车有很很多种,,小轿车车、货车车、客车车,有的的车是客客货两用用,有的的车水陆陆两用21设计原则则:组合合优先如果使用用继承来来描述::一旦增加加新的汽汽车种类类或用途途,都需需要大量量改动原原有代码码22设计原则则:组合合优先使用“组组合”思思路考虑虑问题“汽车”拥拥有某种种或某些些“用途途”“汽车””和“用用途”独独立变化化,互不不影响23设计原则则:组合合优先区分“Is-A”与“Has--A”有一个系系统需要要描述经经理、雇雇员和学学生它们都是是人,所所以:24设计原则则:组合合优先问题有些人既既是经理理,又是是学生,,比如某某位在读读MBA的老总25设计原则则:组合合优先换一个角角度看问问题雇员、经经理、学学生其实实都是角角色的一一种人拥有角角色26Bridge((桥梁)模式是什么导导致设计计的不完完美?变化,无无法避免免的、经经常的需需求变化化设计者的的理想当需求变变化的时时候,尽尽可能少少的修改改代码就就可以满满足新的的需求27设计原则2:封装可变性发现代码容易变化的部分,封装之,使它和不容易变化的部分独立开来Bridge((桥梁)模式“发现变变化点””28Bridge((桥梁)模式“封装变变化点””变化点1:小鸟一一家29Bridge((桥梁)模式“封装变变化点””变化点2:鸟类的的行为——飞30Bridge((桥梁)模式“封装变变化点””变化点2:鸟类的的行为——游泳31Bridge((桥梁)模式“使变化化点和不不变点独独立开来来”在这个例例子里其其实是两两个变化化点相独独立“鸟类””和“行行为”什什么关系系?鸟类拥有行为鸟类行为为的具体体实现,,委托““行为””类来完完成32鸟儿拥有有飞、游游泳的行行为33Bridge((桥梁)模式使用桥梁梁模式的的效果比如增加加一种鸟鸟类“鹅鹅”,相相应的要要增加一种游泳泳的行为为“红掌掌拨清波波”只需要增加一个鸟类类的子类类“鹅””增加一个游泳泳的行为为“红掌掌拨清波波”设置“鹅鹅”的飞飞翔行为为为“飞飞不起来来”设置“鹅鹅”的游游泳行为为为“红红掌拨清清波”原有代码码不需要要改动!!34Bridge((桥梁)模式35Bridge((桥梁)模式使用桥梁梁模式的的效果当需求改改变的时时候(增增加动物物或行为为),只只需要简简单添加加几个类类对原有代代码不需需要改动动保证了代代码的稳稳定,提提高了可可维护性性36设计原则3:开-闭原则在设计一个软件的时候,应当使这个软件可以在不被修改的前提下扩展Bridge((桥梁)模式结构37Bridge((桥梁)模式意图将抽象部部分与它它的实现现部分分分离,使使它们都都可以独独立地变变化适用性抽象和它它的实现现部分可可以独立立变化类的抽象象以及它它的实现现都可以以通过生生成子类类的方法法加以扩扩充实现部分分的修改改不会对对客户产产生影响响.......38Bridge((桥梁)模式应用举例例1:“小朋朋友画画画”使用蜡笔笔需要大中中小三种种型号每种型号号各有12种颜色共36支39Bridge((桥梁)模式使用毛笔笔:大、中、、小3支毛笔12种颜料40Bridge((桥梁)模式蜡笔和毛毛笔的差差别蜡笔:笔笔和颜色色无法分分离,因因此需要要36种蜡笔毛笔:笔笔和颜色色可以独独立选择择,因此此只有3+12=15个子类体现了Bridge模式将继承关关系转换换为组合合关系,,从而降降低了系系统间的的耦合,,减少了了代码冗冗余41Bridge((桥梁)模式应用举例例2有一个CAD软件,可可以画多多种图形形同时支持持多套绘绘图算法法传统的设设计42Bridge((桥梁)模式应用Bridge模式43Bridge((桥梁)模式分析图形Shape是一个抽抽象概念念,它可可以有许许多具体体化(变化点1)图形的显显示Drawing是图形的的实现,,它也可可以有许许多套算算法(变化点2)Bridge模式使用用组合代代替继承承,避免免了复杂杂的继承承体系,,使得两两个变化化点独立立变化,,互不影影响44设计原则则:开-闭原则、、封装可可变性“开-闭”原则则BertrandMeyer:““Softwareshouldbeopenforextension,,butclosedformodification”在设计一一个软件件的时候候,应当当使这个个软件可可以在不不被修改改的前提提下扩展展解释已有模块块,尤其其是最重重要的抽抽象层模模块不能能动:保保证稳定定性和延延续性可以扩展展新模块块:增加加新行为为,保证证灵活性性45设计原则则:开-闭原则、、封装可可变性BertrandMeyer对象技术术大师法国工程程院院士士苏黎世工工学院计计算机系系教授发明了Eiffel语言和按按契约设设计(DesignbyContract))的思想早年参与与了Z形式语言言的设计计名著《面向对象象软件构构造》46设计原则则:开-闭原则、、封装可可变性玉帝遵照照“开-闭”原则则维护天天庭秩序序当年孙悟悟空大闹闹天空,,向天庭庭发出挑挑战:““皇帝轮轮流做,,明年到到我家.......只教他搬搬出去,,将天宫宫让与我我!”太白金星星给玉皇皇大帝建议道::“降一一道招安安圣旨,把把他宣来来上界...与他籍名名在箓...一则不动动众劳师师,二则收仙仙有道也也。”47设计原则则:开-闭原则、、封装可可变性分析“不动众众劳师””、不破破坏天规规就是““闭”收仙有道道就是““开”招安,就就是玉帝帝的“开开-闭”原则则:既让让孙悟空空满意,,又不必必更改天天庭现有有的秩序序48设计原则则:开-闭原则、、封装可可变性分析现有的天天庭秩序序是系统统的最高高抽象层层弼马温这这个职位位只是具具体的实实现层招安的关关键就是是不允许许更改现现有的天天庭秩序序,但是是允许将将妖猴纳纳入到文文武百官官中,从从而扩展展了这一一秩序的的具体实实现49设计原则则:开-闭原则、、封装可可变性“封装可可变性原原则”gof:“考虑虑你的设设计中什什么可能能会发生生变化.......考虑你允允许什么么发生变变化而不不让这一一变化导导致重新新设计””Shalloway:“发现现变化点点,并封封装之””一种可变变性不应应散落在在代码的的很多角角落一种可变变性不应应当与另另一种可可变性混混合在一一起50设计原则则:开-闭原则、、封装可可变性设计模式式对“开开-闭”原则则的支持持比如Bridge桥梁模式式:将抽抽象部分分和实现现部分分分别封装装,可以以分别独独立变化化51设计原则则:开-闭原则、、封装可可变性对“开-闭”原则则支持的的不好的的例子java.util..Calendar52java提供的描描述历法法的抽象象类描述公历历的子类我们希望望再派生生出一个个子类,,用于描描述阴历历设计原则则:开-闭原则、、封装可可变性问题:Calendar只定义了了适用于于公历的的常量和和方法53publicfinalstaticintSUNDAY==1;publicfinalstaticintMONDAY==2;...publicfinalstaticintJANUARY==0;;publicfinalstaticintFEBRUARY==1;;...publicvoidsetFistDayOfWeek(intvalue);;publicintgetFirstDayOfWeek());...设计原则则:开-闭原则、、封装可可变性问题英文的星星期、月月份名称称不符合合中国阴阴历的叫叫法阴历以10天为一周周,公历历和阴历历每月的的天数也也不同,,所以Calendar关于星期期、月份份的算法法不适合合阴历总之,Calendar无法容纳纳中国阴阴历,因因此不支支持“开开-闭”原则则54Strategy(策略)模式桥梁模式式使得两个个变化点点的独立立55设计原则则找出应用用中可能能需要变变化之处处把它们独独立出来来不要和那那些不需需要变化化的代码码混在一一起56Strategy(策略)模式单独看飞飞的行为为的实现现策略模式式:封装装了一系系列算法法,使得得它们可可以相互互替换效果:算算法可以以独立变变化57设计原则则针对接口口编程,,而不是是针对实实现编程程58策略模式式-开闭原则则.例-计算价格格PublicclassPart{privatedoublebasePrice;;publicvoidsetPrice(doubleprice)){basePrice==price;}publicdoublegetPrice(){{returnbasePrice;}}59某类方法Publicdoubletotalprice((Part[]]parts){doubletotal==0.0;for((inti=0;;i<parts.length;;i+++){total++=parts[i].getPrice());}returntotal;;}60思考内存折扣扣?61方法Publicdoubletotalprice((Part[]]parts){doubletotal==0.0;for((inti=0;;i<parts.length;;i+++){if(parts[I]instanceofMemory)total++=parts[i].getPrice())*0.9;elsetotal++=parts[i].getPrice());}returntotal;;}62思考符合OCP吗?63方法?PublicclassMemoryextendsPart{publicdoublegetPrice(){{returnbasePrice*0.9;}}64更好的方方法?采用一个个PricePolicy类,通过过对其进进行继承承以提供供不同的的计价策策略65方法PublicclassPart{privatePricePolicypricePolicy;publicvoidsetPricePolicy(PricePolicypolicy)){pricePolicy==policy;}publicvoidsetPrice(doubleprice)){pricePolicy.setPrice(price));}publicdoublegetPrice(){{returnpricePolicy..getPrice(();}}66价格策略略PublicclassPricePolicy{{privatedoublebasePrice;;publicvoidsetPrice(doubleprice)){basePrice==price;}publicdoublegetPrice(){{returnbasePrice;}}67销售策略略PublicclassSaleextendsPricePolicy{privatedoublediscount;publicvoidsetDiscount(doublediscount)){this.discount=discount;;}publicdoublegetPrice(){{returnbasePrice*discount;;}}68Strategy(策略):定义所所有支持持的算法法的公共共接口ConcreteStrategy(具体策略略):实现具具体算法法Context(上下文):用一个ConcreteStrategy对象来配配置维护一个个对Strategy对象的引引用可定义一一个接口口来让Strategy访问它的的数据69阶段小结结设计原则则70限制变化化的影响响范围增加新功功能,要要做到只只增加新新代码,,而不改改动老代代码尽量用组组合,而而不是继继承组合优先先开-闭原则封装可变变性阶段小结结策略模式式使得算法法可以独独立变化化使用组合合取代继继承,封封装了可可变性,,保证了了“开-闭”桥梁模式式使得抽象象和实现现独立变变化避免了两两个变化化点的耦耦合71Adapter(适配器)模式例子1:“不合合适的插插座”你的电脑脑的插头头是三相相的而墙上的的插座只只有两相相的插头和插插座的““接口””不匹配配,怎么么办?72Adapter(适配器)模式例子2:HuntBird游戏中,,希望增增加一种种鸟类““鸭子””但是发现现以前有有一个系系统中已已经有了了“鸭子子”类,,希望重重用老代代码73Adapter(适配器)模式新老代码码接口不不一致74Adapter(适配器)模式疑问把老代码码修改一一下不就就可以了了么?如如下:75Adapter(适配器)模式否定首先,老老代码不不一定允允许修改改比如可能能根本没没有代码码,只有有链接库库其次,修修改代码码工作量量可能很很大容易出错错还记得““开-闭原则””么76Adapter(适配器)模式应用(对象)适配器模模式实现现接口转转换77Adapter(适配器)模式理解1:接口转转换78客户(鸟)被适配者(鸭子)适配器请求转换后的请求Adapter(适配器)模式79叫呷呷叫Adapter(适配器)模式理解2:重新包包装,改改变接口口80Adapter(适配器)模式类适配器器81Adapter(适配器)模式结构对象Adapter82Adapter(适配器)模式结构类Adapter83Adapter(适配器)模式意图将一个类类的接口口转换成成客户希希望的另另外一个个接口Adapter模式使得得原本由由于接口口不兼容容而不能能一起工工作的那那些类可可以一起起工作84Adapter(适配器)模式应用举例例1我们打算算编写一一个画图图软件其中画圆圆形已经经有了一一个现成成的类但是接口口不同,,不能直直接使用用85Adapter(适配器)模式使用对象象Adapter86Adapter(适配器)模式应用举例例2缺省适配配模式——“鲁达剃度度”凡是和尚尚都应该该如此::87Adapter(适配器)模式但是鲁智智深并不不是这样样88鲁智深::习武(){拳打镇关关西();大闹五台台山();倒拔垂杨杨柳();火烧瓦官官寺();}Adapter(适配器)模式所以当初初鲁达剃剃度时,,众僧说说:“这个人人形容丑丑恶,相相貌凶顽顽,不可可剃度””89?Adapter(适配器)模式但是长老老却说::“此人上上应天星星,心地地刚直。。虽然时时下凶顽顽,命中中驳杂,,久后却却得清静静。证过过非凡,,汝等皆皆不及他他”90Adapter(适配器)模式“天星””就是缺缺省适配配器当你不想想/不能实现现接口的的所有方方法时利用缺省省适配器器类,提提供这些些方法的的缺省实实现从这个类类再派生生出的子子类就可可以不去去实现那那些不想想实现的的方法了了91真实世界界中的适适配器想一想Java语言中不不同版本本中有没没有需要要进行适适配的92真实世界界中的适适配器早期java版本中集集合(Collection)类型((例如::Vector,,Stack,,Hashtable)都实现了了一个elements())方法。该该方法返返回一个个Enumeration(枚举))新版本中中开始使使用Iterator(迭代器器)接口口,这个个接口和和枚举接接口很像像,但不不同的是是,迭代代器还提提供了删删除元素素的能力力。93问题面对遗留留代码,,这些代代码会暴暴露出枚枚举器接接口,但但我们又又希望在在新的代代码中只只使用迭迭代器。。解决办法法构造一个个适配器器将枚举适适配到迭迭代器949596publicclassEnumerationIteratorimplementsIterator{///适配器看看起来就就是一个个Iterator///我们使用用组合的的方式,将枚举结结合进适适配器中中,用实例变变量记录录Enumerationenumeration;publicEnumerationIterator(Enumerationenumeration){{this.enumeration=enumeration;;} ///迭代器的的hasNext其实是委委托给enumeration的hasMoreElements方法publicbooleanhasNext(){{returnenumeration..hasMoreElements();;} ///迭代器的的next其实是委委托给enumeration的nextElement方法publicObjectnext((){{returnenumeration..nextElement((); }//很不幸,我们不能能支持迭迭代器的的remove方法,所以必须须放弃,这里是抛抛出一个个异常publicvoidremove((){{thrownewUnsupportedOperationException((); }}97实例有一个类类(adaptee)实现了数数学中的的幂次运运算,方方法中需需要传入入两个参参数,一一个是基基数base,另外一一个是幂幂次exp。现在客客户端需需要一个个求得一一个数的的平方的的函数接接口(target),传入一一个数,,得到它它的平方方值。为为了复用用已经存存在的类类adaptee,使用Adapter来适配adaptee,adapter实现了target接口。9899在架构层层次上的的应用JDBC驱动软件件与适配配器模式式JDBC给出一个个客户端端通用的的界面。。每个数数据库引引擎的JDBC驱动软件件都是一一个介于于JDBC接口和数数据库引引擎接口口之间的的适配器器软件抽象的JDBC接口和各各个数据据库引擎擎的API之间都需需要相应应的适配配器软件件,即为为各个数数据库引引擎准备备的驱动动软件。。100JDBC/ODBC桥梁如果没有有合适的的JDBC驱动软件件,用户户也可以以通过ODBC驱动软件件把JDBC通过一个个JDBC/ODBC桥梁软件件与ODBC驱动软件件连接起起来,从从而达到到连接数数据库的的目的。。101设计原则则:里氏氏代换原原则例子1:“圆是是不是椭椭圆?””在几何学学里,圆圆是椭圆圆的一种种特殊情情况因此,把把椭圆看看作父类类,把圆圆作为子子类102设计原则则:里氏氏代换原原则问题椭圆有长长轴、短短轴圆会完全全继承下下来这些对于于圆来说说毫无意意义类似的::“正方方形不是是矩形””103Circlecircle;circle..GetMajorAxis();;设计原则则:里氏氏代换原原则例子2:“企鹅鹅不是鸟鸟的子类类”凡是鸟都都会飞但是企鹅鹅不会104设计原则则:里氏氏代换原原则例子3我们需要要设计一一个类FileName来描述文文件名,,而文件件名不就就是一个个特殊的的字符串串么?所所以我们们如此设设计:105设计原则则:里氏氏代换原原则问题凡是字符符串都支支持相加加操作,,也就是是说两个个字符串串相加,,结果还还是一个个字符串串可是两个个文件名名相加,,还是一一个合法法的文件件名么??比如:““c:\a.txt”++““d:\\b.txt””结果是::“c:\a.txtd::\b..txt”106设计原则则:里氏氏代换原原则错在哪里里?墨子论““取譬””“白马,,马也;;乘白马马,乘马马也。骊骊马,马马也;乘乘骊马,,乘马也也。”解释:白白马、骊骊马(黑马)都是马,,既然马马可以骑骑,那么么白马和和骊马肯肯定也可可以骑107设计原则则:里氏氏代换原原则LiskovSubstitutionPrinciple一个软件件如果使使用的是是一个父父类的话话,如果果把该父父类换成成子类,,它不能能察觉出出父类对对象和子子类对象象的区别别也就是凡凡是父类类适用的的地方子子类也适适用继承只有有满足里里氏代换换原则才才是合理理的108设计原则4:里氏代换原则凡是父类适用的地方子类应当也适用设计原则则:里氏氏代换原原则反过来的的代换不不成立子类适用用的地方方不要求求父类一一定能适适用墨子又说说“娣,美美人也,,爱娣,,非爱美美人也.......盗,人也也,恶盗盗,非恶恶人也””妹妹是美美女,哥哥哥喜欢欢妹妹,,并不是是因为喜喜欢美女女小偷是人人,讨厌厌小偷,,并不讨讨厌所有有人109设计原则则:里氏氏代换原原则Java语言对此此类问题题的防范范它的String类是final的,不能能继承正确的方方法使用Adapter模式110设计原则则:里氏氏代换原原则Java中的反例例它的Stack类是从Vector类继承下下来的“栈不就就是施加加了访问问限制的的数组么么?”所以“StackIs-AVector”111设计原则则:里氏氏代换原原则用里氏代代换原则则来判断断凡是数组组行得通通的地方方,换成成栈也行行得通么么?Vector可以随机机访问,,可以任任意修改改里面的的元素...这些都是是Stack所不允许许的因此Stack不能从Vector继承下来来,它不不能拥有有Vector的接口112设计原则则:里氏氏代换原原则看看C++STL是怎么办办的STL中的stack其实是一一个Adapter113template<classT,classCont=deque<<T>>>classstack{{public:voidpush(constvalue__type&x){c..push_back(x));}}voidpop(){{c..pop_back((x);;}protected:Contc;;};设计模式式-工厂厂模式当看到““new””,就会想想到“具具体”115116一个计算算器例子子publicclassOperation{privatedoublenumberA=0;;privatedoublenumberB=0;;publicvirtualdoubleGetResult(){{doubleresult=0;;returnresult; }}classOperationAdd::Operation{{publicoverridedoubleGetResult()){doubleresult=0;;result==numberA++numberB;returnresult;}当遇到一一群相关关的具体体类时,,通常见见到下面面的代码码OperationcreateOperation(Stringoperate){Operationoper;switch((operate){{case”+””:oper=newOperationAdd());break;case”=””:oper=newOperationSub());break;case”*””:oper=newOperationMul());break;……...}}117如果计算算器要增增加更多多的运算算类型怎怎么办?118简单工厂厂开始封装装创建对对象的代代码建立一个个简单工工厂当需要Operation时,就叫叫工厂做做一个119定义简单单工厂120PublicclassOperationFactory{publicstaticOperationcreateOperate(Stringoperate){{Operationoper=null;switch((operate){{case”+””:oper=newOperationAdd());break;case”=””:oper=newOperationSub());break;case”*””:oper=newOperationMul());break;case”/””:oper=newOperationDiv());break;}returnoper;;}}121简单工厂厂实现客户端的的实现Operationoper;oper=OperationFactory.createOperate(“++”);;oper.NumberA==1;oper.NumberB==2;doubleresult=oper.GetResult(();122简单工厂厂模式的的优点123简单工厂厂类中包包含了必必要的逻逻辑判断断,根据据客户端端的选择择条件动动态实例例化相关关的类,,对于客户户端来说说,去除除了与具具体产品品的依赖赖。就像计算算器,让让客户端端不用管管该用哪哪个类的的实例,,只要把把‘+’给工厂厂,工厂厂自动就就给出了了实例,,客户端端只要去去做运算算就可以以了,不不同的实实例会实实现不同同的运算算。简单工厂厂实现了了责任的的分割。。问题如果要加加一个““求M数的N此方”的的功能,,就要在在原有方方法中加加一个分分支条件件,就要要修改原原有的类类,违背背了开放-封闭原则,于于是工厂厂方法就就来了。。124定义工厂厂方法模模式工厂方法法模式定定义了一一个创建建对象的的接口由子类决决定实例例化的类类是哪一一个工厂方法法使一个个类的实实例化延延迟到其其子类。。125遵循倒置置依赖原原则的指指导方针针变量不可可以持有有具体类类的引用用如果使用用new,就会持持有具体体类的引引用可以改用用工厂来来避开这这样的做做法不要让类类派生自自具体类类如果派生生自具体体类,就就会依赖赖具体类类请派生自自一个抽抽象(接接口或抽抽象类))不是随时时都要遵遵循这个个原则如直接实实例化字字符串对对象126应用依赖赖倒置原原则要依赖抽抽象,不不要依赖赖具体类类我们把工工厂类抽抽象出一一个接口口,这个个接口只只有一个个方法,,就是创创建抽象象产品的的工厂方方法。然后,所所有的要要生产具具体类的的工厂,,就去实实现这个个接口。。这样,一一个简单单工厂模模式的工工厂类,,就变成成了一个个工厂抽抽象接口口和多个个具体生生产对象象的工厂厂。于是,我我们要增增加‘求求M数的N次方’的的功能时时,就不不需要更更改原有有的工厂厂类了,,只需要要增加此此功能的的运算类类和相应应的工厂厂类就可可以了。。127工厂方法法模式实实现128工厂方法法模式实实现先构建一一个工厂厂接口InterfaceIFactory{OperationCreateOperation();;}129然后加减减乘除各各建一个个具体工工厂去实实现这个个接口classAddFactory:IFactory{publicOperationCreateOperation()){returnnewOperationAdd());}}classSubFactory:IFactory{publicOperationCreateOperation()){returnnewOperationSub());}}130工厂方法法模式实实现然后加减减乘除各各建一个个具体工工厂去实实现这个个接口classMulFactory:IFactory{publicOperationCreateOperation()){returnnewOperationMul());}}classDivFactory:IFactory{publicOperationCreateOperation()){returnnewOperationDiv());}}131工厂方法法模式实实现客户端的的实现IFactoryoperFactory==newAddFactory();;Operationoper==operFactory.CreateOperation());oper.NumberA==1;oper.NumberB==2;doubleresult=oper.GetResult(();132工厂方法法模式实实现工厂方法法模式实实现时,,客户端需需要决定定实例化化哪一个个工厂来来实现运运算类,选择判判断的问问题还是是存在的的,也就就是说,,工厂方方法把简简单工厂厂的内部部逻辑判判断转移移到了客客户端代代码来进进行。如果要加加功能,,本来是是改工厂厂类的,,而现在在是修改改客户端端。133工厂方法法模式一个抽象象产品类类,可以以派生出出多个具具体产品品类。一一个抽抽象工厂厂类,可可以派生生出多个个具体工工厂类。。每个具体体工厂类类只能创创建一个个具体产产品类的的实例。。134工厂方法法模式雷锋工厂厂雷锋是众众人皆知知的做好好人好事事的模范范。作为一名名大学生生,每个个人都可可以以雷雷锋做好好事的名名义去帮帮助老人人。在这里,,’雷锋’类,拥有有扫地、、洗衣、、买米等等方法。。‘学雷锋锋的大学学生’类类是‘雷雷锋’类类的一个个继承。。而大学生生是要毕毕业的,,帮助老老人是长长期的,,所以‘‘社区志志愿者’’更适合合。于是,增增加一个个继承‘‘雷锋’’类的‘‘社区志志愿者’’类。135雷锋类classLeiFeng{publicvoidSweep()){Console.WriteLine(““扫地”); }publicvoidWash(){{Console.WriteLine(““洗衣”); }publicvoidBuyRice(){{Console.WriteLine(““买米”); }}136大学生类类及社区区志愿者者classUndergraduate:LeiFeng{}}classVolunteer::LeiFeng{}}137简单工厂厂模式ClassSimpleFactory{publicstaticLeiFengCreateLeiFeng(stringtyple)){LeiFengresult==null;;switch((type)){case”学雷锋的的大学生生”:result==newUndergradute();;break;;case”社区志愿愿者”:result==newVolunteer());break;}returnresult;}}138客户端的的实现LeiFengstudentA=SimpleFacatory.CreateLeiFeng(“学雷锋的的大学生生”);studentA.BuyRice();;LeiFengstudentB=SimpleFacatory.CreateLeiFeng(“学雷锋的的大学生生”);studentB.Sweep());LeiFengstudentC=SimpleFacatory.CreateLeiFeng(“学雷锋的的大学生生”);studentC.Wash();;139简单工厂厂模式在这里,,需要再再任何实实例化的的时候写写出这个个工厂的的代码。。这里有有重复,,于是用用工厂方方法模式式来写。。140工厂方法法模式InterfaceIFactory{LeiFengCreateLeiFeng(();}classUndergraduteFactory:IFactory{publicLeiFengCreateLeiFeng(){returnnewUndergraduate();;}}141classVolunteerFactory:IFactory{publicLeiFengCreateLeiFeng(){returnnewVolunteer(();}}}客户端代代码Ifactoryfactory==newUndergraduateFactory());LeiFengstudentA=factory.CreateLeiFeng();;LeiFengstudentB=factory.CreateLeiFeng();;LeiFengstudentC=factory.CreateLeiFeng();;studentA.BuyRice();;studentB.Sweep());studentC.Wash();;142工厂方法法模式在这里,,尽管如如果要换换成‘社社区志愿愿者’也也还是要要修改代代码,但但只用修修改一处处就可以以。工厂方法法克服了了简单工工厂违背背开放-封闭原则则的缺点点,又保保持了封封装对象象创建过过程的优优点。它们都是是集中封封装了对对象的创创建,使使得要更更换对象象时,不不需要做做大的改改动就可可实现,,降低了了客户程程序与产产品对象象的耦合合。143工厂方法法模式工厂方法法模式是是简单工工厂模式式的进一一步抽象象和推广广,由于于使用了了多态性性,工厂厂方法模模式保持持了简单单工厂模模式的优优点,而而且克服服了它的的缺点。。但缺点是是由于每每加一个个产品,,就需要要加一个个产品工工厂的类类,增加加了额外外了开发发量。144工厂方法法模式抽象工厂厂模式提供一个个创建一系列相相关或相相互依赖赖对象的的接口,而无需需指定它它们具体体的类。。145定义抽象象工厂模模式146数据访问问程序用户类User,假设只只有ID和Name两个字段段。SqlserverUser类和AccessUser类,用于于操作User表,假设设只有““新增用用户”和和“得到到用户””方法。。SqlserverUser类,用于于访问SQLServer的用户。。AccessUser类,用于于访问Access的用户。。147用工厂方方法模式式的数据据访问程程序148InterfaceIUser{voidInsert(Useruser);UserGetUser((intid);;}classSqlserverUser:IUser{publicvoidInsert((Useruser){Console.WriteLine(““在SQLServer中给User表增加一一条记录录”);}publicvoidGetUser(intid)){Console.WriteLine(““在SQLServer中根据ID得到User表的一条条记录”);returnnull;}}149用工厂方方法模式式的数据据访问程程序classAccessUser:IUser{publicvoidInsert((Useruser){Console.WriteLine(““在Access中给User表增加一一条记录录”);}publicvoidGetUser(intid)){Console.WriteLine(““在Access中根据ID得到User表的一条条记录”);returnnull;}}150工厂方法法IFactory接口:定义一个个创建访访问User表对象的的抽象的的工厂接接口。InterfaceIFactory{IuserCreateUser();;}151SqlServerFactory类,AccessFactory类实现接接口classSqlServerFactory:IFactory{publicIuserCreateUser()){returnnewSqlserverUser();;}}classAccessFactory:IFactory{publicIuserCreateUser()){returnnewAccessUser();;}}152客户端实实现StaticvoidMain(string[]]args)){Useruser==newUser());Ifactoryfactory=newSqlServerFactory(();Iuseriu==factory..CreateUser());iu.Insert((user);;iu.GetUser(1));Console.Read(();}153用抽象工工厂模式式的数据据访问程程序154Idepartment接口,用用于客户户端访问问,解除除与具体体数据库库访问的的耦合。。interfaceIDepartment{{voidInsert(Departmentdepartment));DepartmentGetDepartment(intid));}SqlserverDepartment类,AccessDepartment类分别用用于访问问SQLSever、Access的Department。155classSqlserverDepartment:IDepartment{publicvoidInsert((Departmentdepartment){{Console.WriteLine(““在SQLServer中的Department表增加一条条记录”);}publicDepartmentGetDepartment(intid)){Console.WriteLine(““在SQLServer中根据ID得到Department表中的一一条记录录”);returnnull;}}156classAccessDepartment:IDepartment{publicvoidInsert((Departmentdepartment){{Console.WriteLine(““在Access中的Department表增加一条记录录”);}publicDepartmentGetDepartment(intid)){Console.WriteLine(““在Access中根据ID得到Department表中的一一条记录录”);returnnull;}}157interfaceIFactory{IuserCreateUser();;IDepartmentCreateDepartment();;}classSqlServerFactory:IFactory{publicIuserCreateUser()){returnnewSqlserverUser();;}publicIDepartmentCreateDepartment()){returnnewSqlServerDepartment();;}}158classAccessFactory:IFactory{publicIuserCreateUser()){returnnewAccessUser();;}publicIDepartmentCreateDepartment()){returnnewAccessDepartment();;}}159客户端实实现:StaticvoidMain(string[]]args)){Useruser==newUser());Departmentdept==newDepartment());IFactoryfactory=newAccessFactory(();IUseriu==factory..CreateUser());iu.Insert((user);;iu.GetUser(1));Idepartmentid==factory..CreateDepartment());id.Insert((dept);;id.GetDepartment(1));Console.Read(();}160抽象工厂厂模式的的优点易于交换换产品系系列,由由于具体体工厂类类在一个个应用中中只需要要在初始始化时出出现一次次,这就就使得改改变一个个应用的的具体工工厂变得得非常容容易,它它只需要要改变具具体工厂厂即可使使用不同同的产品品配置。。它让具体体的创建建实例过过程与客客户端分分离,客客户端是是通过它它们的抽抽象接口口操纵实实例,产产品的具具体类名名也被具具体工厂厂的实现现分离,,不会出出现在客客户代码码中。161抽象工厂厂模式多个抽象象产品类类,每个个抽象产产品类可可以派生生出多个个具体产产品类。。一一个个抽象工工厂类,,可以派派生出多多个具体体工厂类类。每每个具体体工厂类类可以创创建多个个具体产产品类的的实例。。162比较工厂厂方法和和抽象方方法抽象工厂厂的需求求:创建建一个产产品家族族负责在抽抽象工厂厂中创建建产品的的方法,,通常是是以“工工厂方法法”来实实现的163FactoryMethod(工厂方法法)模式例子:““去快餐餐厅吃饭饭”164165voidBuyFood(string餐馆,string食品){if(餐馆==""KFC"){{if(食品==""Chicken"))hamburger==newKFCChickenHamburger;elseif(food===""Fish"))hamburger==newKFCFishHamburger;}elseif(restaurant===""McDonald""){{if(food===""Chicken"))hamburger==newMcDonaldChickenHamburger;;elseif(food===""Fish"))hamburger==newMcDonaldFishHamburger;;}}FactoryMethod(工厂方法法)模式增加一种种新的食食物呢??166FactoryMethod(工厂方法法)模式传统设计计的缺点点依赖具体体167voidBuyFood(string餐馆,string食品){if(餐馆==""KFC"){{if(食品==""Chicken"))hamburger==newKFCChickenHamburger;elseif(food===""Fish"))hamburger==newKFCFishHamburger;}...FactoryMethod(工厂方法法)模式“Abstractionshouldnotdependupondetails..Detailsshoulddependuponabstractions”168设计原则5:依赖倒置原则抽象不应当依赖于细节细节应当依赖于抽象设计原则则:依赖赖倒置原原则为什么说说“倒置置”传统的设设计是抽抽象层依依赖具体体层传统的重重用,侧侧重于具具体层次次的模块块,比如如算法、、数据结结构、函函数库因此软件件的高层层模块依依赖低层层模块169传统的依赖方向设计原则则:依赖赖倒置原原则高层依赖赖低层的的问题抽象层包包含的是是系统的的业务逻逻辑和宏宏观的、、战略性性的决定定,是必必然性的的体现具体层则则含有与与实现相相关的算算法和逻逻辑,以以及战术术性的决决定,带带有相当当大的偶偶然性选选择。具具体层经经常有变变动,难难免出现现错误必然依赖赖偶然,,稳定依依赖变动动?170设计原则则:依赖赖倒置原原则依赖具体体的缺点点171设计原则则:依赖赖倒置原原则依赖抽象象抽象一般般不会变变动这样代码码不会受受易变的的具体层层影响172设计原则则:针对对接口编编程如何做到到“依赖赖倒置””?“Programtoaninterface,notanimplementation”173设计原则6:针对接口编程要针对接口编程不要针对实现编程设计原则则:针对对接口编编程“针对接接口编程程”的一一些建议议变量、参参数、返返回值等等应声明明为抽象象类不要继承承非抽象象类不要重载载父类的的非抽象象方法当然这些些只是建建议实际情况况要权衡衡利弊174FactoryMethod(工厂方法法)模式“女娲抟土土造人””《风俗通》:“俗说说天开地地辟,未未有人民民。女娲娲抟黄土土为人。。”175FactoryMethod(工厂方法法)模式简单工厂厂:根据传入入的参数数,决定定创建哪哪一个产产品类对对象176Human*NvWa::CreateHuman((stringname){{if(name==““ZhangSan"")returnnewZhangSan;elseif(name==““LiSi"))returnnewLiSi;elseif(name===““WangErMaZi"))returnnewWangErMaZi;}FactoryMethod(工厂方法法)模式简单工厂厂的优缺缺点优点:实现了责责任分割割利用判断断逻辑,,决定实实例化哪哪一个产产品类客户端可可以免除除直接创创建产品品类对象象的责任任,仅仅仅使用该该产品缺点:没有完全全做到““开-闭”一旦增加加新的产产品,需需要修改改工厂的的代码但是客户户代码不不需要修修改“我不入入地狱谁谁入地狱狱”177FactoryMethod(工厂方法法)模式“女娲举举绳造人人”“女娲抟抟土为人人,剧务务,力不不暇供,,乃引绳绳于桓泥泥中,举举以为人人。”178FactoryMethod(工厂方法法)模式简单工厂厂的问题题所有具体体产品对对象的创创建都放放在一个个类中,,一旦增增加新的的产品,,当然工工厂类要要被修改改工厂方法法:使用用多态来来应对提供一个个抽象工工厂的接接口具体工厂厂分别负负责创建建具体产产品对象象增加新的的产品只只需要相相应增加加新的具具体工厂厂类179FactoryMethod(工厂方法法)模式意图定义一个个用于创创建对象象的接口口,让子子类决定定实例化化哪一个个类使一个类类的实例例化延迟迟到其子子类优点封装了创创建具体体对象的的工作使得客户户代码““针对接接口编程程”,保保持对变变化的““关闭””180FactoryMethod(工厂方法法)模式工厂方法法应用到到“快餐餐店”问问题181Façade((门面、外外观)模式例1:传统的的医院::病人需要要直接跟跟各个部部门打交交道182门诊挂号划价化验取药Façade((门面)模式人性化的的医院接待员代代替病人人进行挂挂号、划划价等病人只需需要和接接待员打打交道183门诊挂号划价取药接待员医院的门门面(Facade)Façade((门面)模式例2:组建家家庭影院院184Façade((门面)模式欣赏一部部电影的的
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 二零二五年度房地产项目纳税担保及贷款担保合同2篇
- 2025年度美容院养生产品研发与品牌孵化合同4篇
- 河南省二零二五年度事业单位劳动合同范本修订解读3篇
- 中英对照专业离婚合同格式(2024年修订版)一
- 2025年度智能速记设备采购协议1分钟速记单词protocol企业采购合同3篇
- 2025年度民办学校教师学生心理健康教育与辅导聘用合同4篇
- 二零二五年度XX地区集体劳动合同履行监督与评价
- 二零二五年度离婚后两个子女居住权保障合同
- 2025年度终止劳动合同及离职员工经济补偿金核算合同
- 二零二五年度车辆半股转让与二手车交易平台合作合同
- 2024年安全教育培训试题附完整答案(夺冠系列)
- 神农架研学课程设计
- 断绝父子关系协议书
- 福建省公路水运工程试验检测费用参考指标
- 《工程勘察资质分级标准和工程设计资质分级标准》
- 小学语文阅读教学落实学生核心素养方法的研究-中期报告
- 眼内炎患者护理查房课件
- 唯物史观课件
- 2021-2022学年四川省成都市武侯区部编版四年级上册期末考试语文试卷(解析版)
- 中国传统文化服饰文化
- 大气污染控制工程 第四版
评论
0/150
提交评论