设计模式和代码重构.pptx
- 文档编号:18630789
- 上传时间:2023-08-23
- 格式:PPTX
- 页数:502
- 大小:3.10MB
设计模式和代码重构.pptx
《设计模式和代码重构.pptx》由会员分享,可在线阅读,更多相关《设计模式和代码重构.pptx(502页珍藏版)》请在冰点文库上搜索。
,设计模式和代码重构,什么是优秀的设计,抗拒变化是无用的,他们不知道自己需要什么,因此也无法提出要求他们知道自己需要什么,但不知道如何说明它他们能够说明,但我们误解了他们我们理解了,但漏掉了隐含的意义、优先级或细节所有这一切都没问题,但市场总会变化,软件需求变更法则,软件不断变更法则:
真实世界中使用的程序必须进行变更,否则它在环境中的作用就会越来越小.,敏捷思想最大的贡献-1,对软件需求变化的态度传统工程学里有一个基本假设是,需要对未来有很详细的计划和预测,有清晰的进度和流程。
但其实软件开发非常不同,它包含很多艺术的成分,人的创造力至关重要,而且软件的需求非常易变。
而敏捷对预测未来的方式是全新的,强调通过提高团队的能力、设计的弹性和流程的灵活性来适应变化。
这种思路对软件开发也是很大的冲击。
案例分析-1,需求描述客户名称:
影片租赁连锁企业统名称:
影片租赁管理系统需求描述:
1:
完成影片连锁企业租赁管理系统,可以计算每一位客户的消费金额和影片的详细信息,金额根据影片的类型和租赁的日期来进行计算.2:
客户把影片分成3类进行管理A:
最新电影B:
普通电影C:
儿童影片.3:
费用计算规则如下a:
是普通电影,如果租期小于2天,费用为2元钱.如果租期大于两天,费用是租期减去2,每天1.5元b:
如果是新片电影,费用为每天3元c:
是儿童电影,如果租期小于3天,费用为1.5元钱.如果租期大于三天,费用是租期减去3,每天1.5元4:
每次客户租赁电影可以为客户积累积分,规则是每次累计增加1分.如果是新片,并且租期大于1天,再增加一分5:
暂且不要考虑系统界面问题和系统的存储问题,总结,增加一个功能特性的成本并不单单是为这些功能编码所花费时间的成本,还应该包括特性扩展的障碍成本。
什么是好的设计,一个好的系统设计应该有如下的性质:
可扩展性、灵活性、可插入性。
好的设计的目标可扩展性(Extensibility):
新的功能可以很容易地加入到系统之中,这就是可扩展性.灵活性(Flexiblity):
可以容许代码修改平稳,而不会波及到很多其他的模块.这就是灵活性可插入性(Pluggability):
可以很容易地将一个类抽出去,同时将另一个有同样接口的类加入进来.这就是可插入性.,开放封闭原则(OCP),软件组成实体(类,模块,函数,等等)应该是可扩展的,但是不可修改的。
即软件实体可以通过增加新代码实现扩展,但是不能修改已有的代码任何系统在其生命周期中都会发生变化。
如果我们希望开发出的系统不会在第一版本后就被抛弃,那么我们就必须牢牢记住这一点。
优秀设计,发现变化/封装变化隔离变化动态绑定解耦具体依赖,适应变化,好的程序设计所面临的最主要的挑战之一就是适应变化.,设计原则1:
发现变化,封装变化,找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起.实现:
把会变化的部分取出并封装起来,以便以后可以轻易地改动和扩充此部分,而不影响不需要变化的其他部分.,抽象稳定接口设计,设计原则2:
抽象稳定接口,针对接口,抽象接口:
创建出固定却能描述一组任意个可能行为的抽象体,这个抽象就像抽象基类或者接口,任意个可能的行为就是可能的派生类.针对接口(抽象)设计:
由于模块子间依赖一个固定的抽象,所以它对于更改可以是关闭的.,设计原则3:
分离变化维度,单一职责原则,单一原则:
就一个类而言,应该仅有一个引起它变化的原因.职责定义为“变化的原因(areasonforchange)”,如果你能够想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责.,静态绑定与动态绑定,代码结构在编译时刻就被确定下来了,比如它由继承关系固定的类组成,或者硬编码实现等。
而程序的运行时刻结构是由快速变化的对象实现。
编译时两个结构是彼此独立的。
蜡笔(粗细的变化和颜色的变化,静态绑定),画笔(粗细的变化和颜色的变化,分离,动态绑定),设计原则4:
尽量动态绑定,组合/聚合复用原则,尽量的使用合成和聚合,而不是继承关系达到复用的目的。
该原则就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分:
新的对象通过向这些对象的委派达到复用已有功能的目的。
多态与继承,继承是多态的基础,多态是继承的目的!
NMPKN+M,解耦具体依赖,4种方式配置文件与反射技术表驱动法惯例优于配置依赖注入,方案1-配置文件与反射技术,将反射技术与配置文件结合,在具体对象拥有共同抽象的前提下,通过配置文件获得具体的对象类型,然后利用反射创建相应对象.,必须知道的设计法则,找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码交织在一起.抽象稳定接口(抽象类),针对接口编程,而不是针对实现编程分离变化维度,单一职责原则动态绑定还是静态绑定,多用组合,少用继承创建与使用分离,创建有变化也要封装,面向对象设计原则,开闭原则,一个设计良好的应用程序应该充分考虑到开发和维护阶段需求的频繁变化,通常情况下,添加一个新的功能需要做出很多修改,我们应该使对已有代码的修改最小化,因为他们已经经过了测试。
对现有代码做出修改将会以一种不可预料的方式影响它们的已有功能。
一个软件实体应该对扩展开发,对修改关闭。
开闭原则是说我们应该努力设计不需要修改的模块。
在扩展系统的行为时,我们只需要添加新的代码,而不需要修改已有的代码。
一般可以通过添加新的子类和重写父类的方法来实现。
开闭原则,满足开闭原则的模块符合下面两个标准:
对扩展开放-模块的行为可以被扩展从而满足新的需求。
对修改关闭-不允许修改模块的源代码。
(或者尽量使修改最小化)怎样实现开闭原则抽象、接口、多态、继承要想使一个软件系统的所有模块都满足开闭原则是不太现实的,不过我们应该努力使大部分模块满足开闭原则。
开闭原则是面向对象设计的核心,满足该原则可以达到最大限度的复用和可维护性。
开闭原则,实例总结像许多其他原则一样,开闭原则只是面向对象设计的一个原则,实现一个灵活的设计需要额外的时间和努力,引入新的抽象层会增加代码的复杂性。
因此,该原则适用于那些需求会经常发生变化的系统。
有许多设计模式可以帮助我们扩展功能而不需要修改代码。
例如,装饰模式等。
单一原则,在本文中职责是指引起变化的原因。
该原则表明,如果你有多个原因去改变一个类,那么应该把这些引起变化的原因分离开,把这个类分成多个类,每个类只负责处理一种改变。
当你做出某种改变时,只需要修改负责处理该改变的类。
当我们去改变一个具有多个职责的类时可能会影响该类的其他功能一个类应该只受一种变化的影响。
单一职责原则简单而直观,但是在实际实现中可能是很困难的。
单一原则,实例总结单一职责原则代表了设计应用程序时一种很好的识别类的方式,并且它提醒你思考一个类的所有演化方式。
只有对应用程序的工作方式有了很好的理解,才能很好的分离职责。
接口隔离原则,当我们设计应用程序的时候,如果一个模块包含多个子模块,那么我们应该小心对该模块做出抽象。
设想该模块由一个类实现,我们可以把系统抽象成一个接口。
但是当我们想要添加一个新的模块扩展程序时,如果要添加的模块只包含原系统中的一些子模块,那么就会强迫我们实现接口中的所有方法,并且还要编写一些哑方法。
这样的接口被称为胖接口或者叫被污染的接口,使用这样的接口将会给系统引入一些不正确的行为。
接口隔离原则表明客户端不应该被强迫实现一些他们不会使用的接口,应该把胖接口中的方法分组,然后用多个接口代替它,每个接口服务于一个子模块。
不应该强迫客户端依赖于他们不会使用的接口。
接口隔离原则,实例总结如果已经设计成了胖接口,可以使用适配器模式隔离它。
像其他设计原则一样,接口隔离原则需要额外的时间和努力,并且会增加代码的复杂性,但是可以产生更灵活的设计。
如果我们过度的使用它将会产生大量的包含单一方法的接口,所以需要根据经验并且识别出那些将来需要扩展的代码来使用它,里氏代换原则,当我们设计程序模块时,我们会创建一些类层次结构,然后我们通过扩展一些类来创建它们的子类。
我们必须确保子类只是扩展而没有替换父类的功能,否则当我们在已有程序模块中使用它们时将会产生不可预料的结果。
里氏代换原则表明当一个程序模块使用基类时,基类的引用可以被子类替换而不影响模块的功能。
基类完全能够被子类替代而不影响模块的功能。
里氏代换原则,实例总结里氏代换原则是对开闭原则的扩展,它表明我们在创建基类的新的子类时,不应该改变基类的行为。
依赖倒转原则,在一个应用程序中,我们有一些实现了基础的、主要的操作的底层类和一些封装了复杂逻辑的上层类。
实现这种结构的很自然地方式就是,先编写底层类,完成后再编写复杂的上层类。
因为上层类是由其他东西定义的,所以这看起来是一种很合理的方式。
但是这不是一个灵活的设计,如果我们需要替换一个底层类时会发生什么?
让我们以经典的拷贝程序为例,它从键盘读取一些字符,然后把他们输出到打印设备上。
包含该逻辑的上层类是Copy类,底层类是KeyboardReader和PrinterWriter。
在一个不好的设计中,上层类直接使用底层的类,在这种情况下,如果我们想要把输出定向到新的FileWriter类,就必须修改Copy类的代码(假设它是一个具有很多逻辑的复杂类并且很难测试)。
为了避免这种问题,我们可以在上层类和底层类之间引入一个抽象层。
因为上层模块包含复杂的逻辑,所以它们不应该依赖于底层模块,新的抽象层也不应该基于底层模块而创建。
底层模块应该基于抽象层而创建。
基于这个原则,设计类结构的方式应该是从上层模块到底层模块。
上层类-抽象层-底层类,依赖倒转原则,上层模块不应该依赖于底层模块,它们都应该依赖于抽象。
抽象不应该依赖于细节,细节应该依赖于抽象。
依赖倒转原则,实例总结应用该原则意味着上层类不直接使用底层类,他们使用接口作为抽象层。
这种情况下上层类中创建底层类的对象的代码不能直接使用new操作符。
可以使用一些创建型设计模式,例如工厂方法,抽象工厂和原型模式。
模版设计模式是应用依赖倒转原则的一个例子。
当然,使用该模式需要额外的努力和更复杂的代码,不过可以带来更灵活的设计。
不应该随意使用该原则,如果我们有一个类的功能很有可能在将来不会改变,那么我们就不需要使用该原则。
迪米特法则,迪米特法则(LawofDemeter)又叫最少知识原(LeastKnowledgePrincipleLKP),就是说一个对象应当对其他对象有尽可能少的了解,不和陌生人说话对面向对象来说,一个软件实体应当尽可能的少的与其他实体发生相互作用。
每一个软件单位对其他的单位都只有最少的知识,而其局限于那些与本单位密切相关的软件单位。
迪米特法则的目的在于降低类之间的耦合。
由于每个类尽量减少对其他类的依赖,因此,很容易使得系统的功能模块相互独立,相互之间不存在依赖关系。
应用迪米特法则有可能造成的一个后果就是,系统中存在的大量的中介类,这些类只所以存在完全是为了传递类之间的相互调用关系-这在一定程度上增加系统的复杂度。
迪米特法则,设计模式中的门面模式(Facade)和中介模式(Mediator)都是迪米特法则的应用的例子。
狭义的迪米特法则的缺点:
在系统里面造出大量的小方法,这些方法仅仅是传递间接的调用,与系统的商业逻辑无关。
遵循类之间的迪米特法则会使一个系统的局部设计简化,因为每一个局部都不会和远距离的对象有之间的关联。
但是,这也会造成系统的不同模块之间的通信效率降低,也会使系统的不同模块之间不容易协调。
广义的迪米特法则在类的设计上的体现:
优先考虑将一个类设置成不变类.尽量降低一个类的访问权限。
尽量降低成员的访问权限。
案例,组合/聚集复用原则,组合/聚合复用原则(Composite/AggregateReusePrincipleCARP).组合和聚合都是对象建模中关联(Association)关系的一种.聚合表示整体与部分的关系,表示“含有”,整体由部分组合而成,部分可以脱离整体作为一个独立的个体存在。
组合则是一种更强的聚合,部分组成整体,而且不可分割,部分不能脱离整体而单独存在。
在合成关系中,部分和整体的生命周期一样,组合的新的对象完全支配其组成部分,包括他们的创建和销毁。
一个合成关系中成分对象是不能与另外一个合成关系共享。
组合/聚合和继承是实现复用的两个基本途径。
合成复用原则是指尽量使用合成/聚合,而不是使用继承。
组合/聚集复用原则,只有当以下的条件全部被满足时,才应当使用继承关系。
子类是超类的一个特殊种类,而不是超类的一个角色,也就是区分“Has-A”和“Is-A”.只有“Is-A”关系才符合继承关系,“Has-A”关系应当使用聚合来描述。
永远不会出现需要将子类换成另外一个类的子类的情况。
如果不能肯定将来是否会变成另外一个子类的话,就不要使用继承。
3子类具有扩展超类的责任,而不是具有置换掉或注销掉超类的责任。
如果一个子类需要大量的置换掉超类的行为,那么这个类就不应该是这个超类的子类。
错误的使用继承而不是合成/聚合的一个常见原因是错误地把“Has-A”当成了“Is-A”.”Is-A”代表一个类是另外一个类的一种;而“Has-A”代表一个类是另外一个类的一个角色,而不是另外一个类的特殊种类。
面向对象设计原则连连看,面向对象的设计模式,创建型模式,工厂模式抽象工厂单例原型构建者,TheFactoryPattern,Factory是最常见的设计模式之一,可帮助我们组织创建对象的代码,通常用于以下两种情况:
创建复杂的对象,并进行初始化。
根据不同的环境(输入参数),创建不同用途的对象。
一般这些对象都是实现了相同的接口或继承于同一基类。
Factory模式的JDBC应用,OracleDataSource负责创建链接,由函数getConnection获取链接,Factory模式应用于DAO,XMLDB是XML数据库访问接口,针对Oracle和DB2分别提供了实现。
XMLDB_DAOFactory为类工厂,根据输入的参数dbtype,创建不同的XMLDB实现类。
更多的Factory模式应用例子,Hibernate的SessionFactory,将数据库表和对象的映射关系写入XML格式的配置文件,然后由SessionFactory根据它来创建Session。
EJB容器本身就是一个EJB的Factory。
当客户端调用EJB的时候,由容器创建EJB供其使用。
抽象工厂模式,抽象工厂模式(别名:
配套)提供一个创建一系列(相互依赖)对象的接口,而无需指定它们具体的类。
AbstractFactoryPattern(AnotherName:
Kit)Provideaninterfaceforcreatingfamiliesofrelatedordependentobjectswithoutspecifyingtheirconcreteclasses.,一、概述,当系统准备为用户提供一系列相关的对象,又不想让用户代码和创建这些对象的类形成耦合时,就可以使用抽象工厂方法模式来设计系统。
抽象工厂模式的关键是在一个抽象类或接口中定义若干个抽象方法,这些抽象方法分别返回某个类的实例,该抽象类或接口让其子类或实现该接口的类重写这些抽象方法,为用户提供一系列相关的对象。
一、一个实例,建立一个系统,该系统可以为用户提供西服套装(上衣裤子)和牛仔套装(上衣裤子)。
二、抽象工厂模式的结构与使用,模式的结构中包括四种角色:
抽象产品(Prodcut)具体产品(ConcreteProduct)抽象工厂(AbstractFactory)具体工厂(ConcreteFactory),模式的UML类图,模式的结构的描述与使用,1抽象产品(Product):
UpperClothes.javapublicabstractclassUpperClothespublicabstractintgetChestSize();publicabstractintgetHeight();publicabstractStringgetName();Trousers.javapublicabstractclassTrouserspublicabstractintgetWaistSize();publicabstractintgetHeight();publicabstractStringgetName();,模式的结构的描述与使用,2具体产品(ConcreteProduct)_1:
WesternUpperClothes.javapublicclassWesternUpperClothesextendsUpperClothesprivateintchestSize;privateintheight;privateStringname;WesternUpperClothes(Stringname,intchestSize,intheight)this.name=name;this.chestSize=chestSize;this.height=height;publicintgetChestSize()returnchestSize;publicintgetHeight()returnheight;publicStringgetName()returnname;,模式的结构的描述与使用,2具体产品(ConcreteProduct)_2:
CowboyUpperClothes.javapublicclassCowboyUpperClothesextendsUpperClothesprivateintchestSize;privateintheight;privateStringname;CowboyUpperClothes(Stringname,intchestSize,intheight)this.name=name;this.chestSize=chestSize;this.height=height;publicintgetChestSize()returnchestSize;publicintgetHeight()returnheight;publicStringgetName()returnname;,模式的结构的描述与使用,2具体产品(ConcreteProduct)_3:
WesternTrousers.javapublicclassWesternTrousersextendsTrousersprivateintwaistSize;privateintheight;privateStringname;WesternTrousers(Stringname,intwaistSize,intheight)this.name=name;this.waistSize=waistSize;this.height=height;publicintgetWaistSize()returnwaistSize;publicintgetHeight()returnheight;publicStringgetName()returnname;,模式的结构的描述与使用,2具体产品(ConcreteProduct)_4:
CowboyTrousers.javapublicclassCowboyTrousersextendsTrousersprivateintwaistSize;privateintheight;privateStringname;CowboyTrousers(Stringname,intwaistSize,intheight)this.name=name;this.waistSize=waistSize;this.height=height;publicintgetWaistSize()returnwaistSize;publicintgetHeight()returnheight;publicStringgetName()returnname;,模式的结构的描述与使用,3抽象工厂(AbstractFactory):
ClothesFactory.javapublicabstractclassClothesFactorypublicabstractUpperClothescreateUpperClothes(intchestSize,intheight);publicabstractTrouserscreateTrousers(intwaistSize,intheight);,模式的结构的描述与使用,4具体工厂(ConcreteFactory):
BeijingClothesFactory.javapublicclassBeijingClothesFactoryextendsClothesFactorypublicUpperClothescreateUpperClothes(intchestSize,intheight)returnnewWesternUpperClothes(北京牌西服上衣,chestSize,height);publicTrouserscreateTrousers(intwaistSize,intheight)returnnewWesternTrousers(北京牌西服裤子,waistSize,height);ShanghaiClothesFactory.javapublicclassShanghaiClothesFactoryextendsClothesFactorypublicUpperClothescreateUpperClothes(intchestSize,intheight)returnnewWesternUpperClothes(上海牌牛仔上衣,chestSize,height);publicTrouserscreateTrousers(intwaistSize,intheight)returnnewWesternTrousers(上海牌牛仔裤,waistSize,height);,模式的结构的描述与使用,5应用_1:
Shop.javapublicclassShopUpperClothescloth;Trouserstrouser;publicvoidgiveSuit(ClothesFactoryfactory,intchestSize,intwaistSize,intheight)cloth=factory.createUpperClothes(chestSize,height);trouser=factory.createTrousers(waistSize,height);showMess();privatevoidshowMess()System.out.println();System.out.println(cloth.getName()+:
);System.out.print(胸围:
+cloth.getChestSize();System.out.println(身高:
+cloth.getHeight();System.out.println(trouser.getName()+:
);System.out.print(腰围:
+trouser.getWaistSize();System.out.println(身高:
+trouser.getHeight();,模式的结构的描述与使用,5应用_2:
Application.javapublicclassApplicationpublicstaticvoidmain(Stringargs)Shopshop=newShop();ClothesFactoryfactory=ne
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 设计 模式 代码