设计模式怎么使用,如何选择设计模式


设计模式的程序没有一个统一的定义,都是开发人员在开发当中不断积累,总结出来的一种可以复制重用的方案。
•    设计模式是对程序设计人员经常遇到的设计问题的可再现的解决方案
•    设计模式建立了一系列描述如何完成软件开发领域中特定任务的规则
•    设计模式关注与复用可重复出现的结构设计方案
•    设计模式提出了一个发生在特定设计环境中的可重复出现的设计问题,并提供解决方案
•    设计模式识别并确定类和实例层次上或组件层次上的抽象关系
总结:设计模式在设计者是一种流行的思考设计问题的方法,是一套被反复使用,多数人知晓的,经过分类编目的,代码设计经验的总结。
使用了设计模式,是为了使代码具有可重用性,让代码更容易被他人理解和保证代码的可靠性。


1.寻找合适的对象-->决定对象的粒度-->指定对象的接口-->描述对象的实现

寻找合适的对象
面向对象的程序由对象组成,对象包括数据和对数据进行操作的过程,对象在收到客户的请求之后会执行相应的操作。客户请求是使对象执行操作的唯一办法,操作又是对象改变的内部数据的唯一方法,最困难的就是将系统分解为对象集合,要考虑许多元素:封装、粒度、依赖关系、灵活性、性能、演化、复用等,这些都影响着系统的分解,并且一般时候这些元素还是互相冲突。
设计的许多对象来源于现实世界的分析模型,但是设计结果所得到的类通常在现实世界是不存在的,如果严格的反映当前世界的模型并不能产生也能反应将来世界的系统,所以设计中的抽象对于产生灵活的设计至关重要。
设计模式帮你确定并不明显的抽象和描述这些抽象的对象,这些对象在分析阶段甚至在设计阶段的早期都不存在,后来为了使设计更灵活才将它们创建出来。

决定对象的粒度

对象在大小和数目上变化极大,它们能表示下到硬件上到整个应用的任何事物,怎样决定一个对象是什么,这是一个非常麻烦的问题,首先每个人看待问题的视角不同对问题的理解不同,所以细分问题的大小不同导致对象的粒度没有一个明确的规定,但是设计面向对象的初衷不会变,设计面向对象的目的不会变,所以能够达到这个目的并解决问题的是设计模式,这些模式是如何对待对象粒度本省就是一个很好的参考,一些设计模式会描述如何支持大量的最小粒度、描述将一个对象分解为许多小对象等等。

指定对象的接口

对象操作所定义的所有操作型构的集合被称为接口,该接口描述了该对象所能接受的全部请求,任何匹配对象接口中型构的请求都可以发送給该对象。
类型是用来标识特定接口的一个名字,如果一个对象接受某个接口所定义的所有操作请求,就可以认为该对象具有这个类型,接口可以包含其他接口作为子集,当一个类型的接口包含另外一个类型的接口时,我们就说它是另一个类型的子类型。当給对象发送请求时,所引起的具体操作与请求本身和接受的对象有关,支持相同请求的不同对象可能对请求激发的操作有不同的实现,发送給对象的请求和它相应的操作在运行时刻的连接称之为动态绑定,即是指发送的请求直到运行的时刻才受你的具体实现的约束。
设计模式根据通过确定接口的主要组成部分及接口发送的数据类型,来帮助使用者定义接口,还会告诉使用者不能包含哪些东西,同时也指定了接口之间的关系。

描述对象的实现

对象的实现是由类定义的,类指定了对象内部的数据和表示,也定义了对象能够完成的操作。
抽象类的主要目的是为了它的子类定义公共接口,一个抽象类将把它的部分或全部操作的实现延伸到子类中。而混入类是给其他类提供可选择的接口或功能的类,域抽象类一样不能实例化。
类继承与接口的比较:首先理解对象的类与对象的类型的区别很重要,一个对象的类定义了对象是怎么实现的,但是对象的类型只与它的接口有关,不同类的对象具有相同的类型,同时对象的类和类型也是具有紧密联系的,因为类定义了对象所能执行的操作,也定义了对象的类型,当说一个对象是一个类的实例时,即指该对象支持类所定义的接口。然后回到继承和接口,类继承根据一个对象的实现定义了另外一个对象的实现,简而言之就是代码和表示的共享机制,但是接口继承描述了一个对象什么时候可以被另外一个对象替代,很多语言不区分这两个概念,所以容易混淆。尽管大部分设计语言不区分接口继承和实现继承这两个的区别但是使用中还是分别对待它们,很多设计模式依赖于这种差别,比如说一个模式中的对象必须有一个公共类型,但一般情况下它们不具有公共的实现。
对接口编程,虽然类继承允许从已存在的类中继承所需要的绝大部分功能,就可以获得新的实现,然和实现的复用只实现了一半,定义具有相同接口的对象族这一功能很重要,因为多态需要这种能力,只根据抽象接口编程有两个好处:客户无需知道使用对象的特定类型,只需对象有客户所期望的类型,无须知道使用的对象是用什么类来实现的,只须知道定义接口的抽象类。这将极大的减少子系统实现之间的相互依赖关系,也产生了可复用的看向对象的设计原则,针对接口编程而不是针对实现编程。
不将变量声明某个特定的具体类的实例对像,而是遵从抽象类所定义的接口。

2.运用复用机制-->关联运行时刻和编译时刻的结构-->设计应支持变化


运用复用机制

这是重中之重,是面向对象最关键的地方,也是一个设计好坏的关键。
理解对象、接口、类和继承之类并不难但是关键在于如何运用好,面向对象系统中的功能复用最常用的两种是对象组合和类继承。
类继承:允许你根据其他的类实现来定义一个类的实现,这种通过生成子类的复用方式称为白箱复用,这个白箱是相对可视性而言:在继承中父类的内部细节对子类可见。
对象组合:更复杂的功能可以通过组装活组合对象来获得,对象组合要求被组合的对象具有良好的接口,这种复用风格被称为黑箱复用:因为对象的内部细节都是不可见的。
继承和组合都是各有优缺点的,类继承是在编译时刻静态定义的且可以直接使用,因为程序设计语言直接支持类继承,类继承可以较方便的改变被复用的实现,但是继承被认为是破坏了封装性,子类的实现与他的父类有紧密的依赖关系,父类实现的任何变化必然会导致子类发生变化,无法在运行的时候进行改变从父类继承的实现。当需要复用子类的时候,实现上的依赖就会产生一些问题,如果继承下来的实现不适合解决新的问题则父类就会被重写,这样限制了灵活性并最终限制了复用性,有一个解决的方案继承抽象类因为抽象类通常提供较少的实现。
对象组合是通过获得其他的对象的引用而在运行时刻动态定义的,组合要求对象遵守彼此的接口约定。因为对象只通过接口访问,只要类型一样运行时刻还可以用一个对象来替代另外一个对象,更进一步因为对像的实现是基于接口写的,所以实现上较少的具有依赖关系。优先使用对像组合有助于保持每个类被封装并集中在单个任务中,基于对象组合的设计会有更多的对象而又较少的类,系统运行将依赖于对像间的关系而不是被定义在某个类中。
在理想情况下不应该为了获得复用而去创建新的构建,应该能够只使用对像组合技术,通过组装已有的构件就能获得你需要的功能,但是构件并不够丰富所以通过继承的复用使新的构建的创建比组装已有构件要容易,一般继承和对象一般一起使用。
委托是一种组合方式,使组合具有与继承同样的复用能力,在委托方式下有两个对象处理一个请求,接受请求的对象将操做委托给它的代理者,这类似于子类将请求交给它的代理者,类似于子类将请求交给它的父类来处理。委托方式为了得到同样的效果接受请求的对象将自己传給委托者,使被委托的操作可以引用接受请求的对象。
委托与那些通过对象组合的义取得软件灵活性的技术一样具有不足:动态高度参数化的软件比静态的软件更难于理解,委托是对象组合的特例它告诉你对象组合作为一个代码复用机制可以替代继承。
还有另外一种功能复用技术是参数化类型,也就是类属或模版。它允许你在定义一个类型的时候并不指定,该类型所用到的其他所有类型,未经指定的类型在使用时以参数形式提供,一个列表类能够以它所包含元素的类型来进行参数化。参数化类型给我们提供了类继承和对象组合外的第三种方式来组合面向对象系统中的行为。
这些技术存在着极大的不同,对象组合技术允许你在运行时刻改变组合的行为,但是它存在间接性,比较低效。继承允许你提供操作的缺省实现,并通过子类重定义这些操作,参数化类型允许改变类所用到的类型、但是继承和参数化类型都不能在运行的时刻改变。

关联运行时刻和编译时刻的结构

一个面向对象程序运行时的结构和它的代码结构相差甚大,代码结构在编译时刻被确定下来,由继承关系固定的类组成。运行时刻结构是由快速变化的通信对像网络组成。这两个结构相互独立。这时就要考虑聚合和相识的差别:聚合意味着一个对象拥有另外一个对象或对另外一个对象负责,一般称一个对象包含另一个对象或者是另一个对象的一部分,聚合意味着聚合对象和其所有者具有相同的生命周期。相识意味着一个对象仅仅知道另外一个对象,也被称为关联或者引用,相识的对象可能请求彼此的操作,是一种比聚合要弱的关系,只表示了对象间的耦合关系。聚合和相识很容易混淆因为通常以相同的方法实现。从根本上讲,是聚合还是相识是根据使用者的意图而不是显示的语言机制决定,在编译时刻很难看出区别,聚合使用较少且比相识关系更持久而相识的出现的频率很高但有时只存在一个操作期间,相识更具有动态性。
程序运行时刻结构和编译时刻结构存在这么大的差别,代码不可能揭示关于系统是如何工作的全部信息,系统运行的时刻更多受到设计者的影响而不是编程语言,

设计应该支持变化

获得最大限度复用的关键在于对新需求和已有需求发生变化时的预见性,要求系统设计能够相应的改进,要为了完成这种设计,就必须要考虑系统的运行周期内会发生什么变化,设计模式可以确保系统能以特定方式变化,从而帮助你避免重新设计系统,设计模式允许系统结构的某个方面的变化独立于其他方面,设计模式在开发如下三类主要软件的中所起的作用:应用程序、工具箱、框架。
应用程序:应该优先考虑内部复用性、可维护性、可扩充性,内部复用性不会做多余的设计,设计模式通过减少内部依赖性来提高内部复用性,松散耦合也增强了一类对象与其他多个对象协作的可能性也会增强可扩充性。
工具箱:一个应用会经常使用来自一个或多个被称为工具箱的预定义类库的类,工具箱时一组相关的可复用的类的集合,这些类提供了通用的功能,工具箱强调的是代码复用,是面向对象环境下的子程序库,只是为你的应用提供功能上的帮助。工具箱的设计要比应用程序难得多,因为要对许多应用是可用的和有效的。要避免假设和依赖就变得很重要因为不知道工具箱要用到什么地方,会影响到效率和适用性。
框架:是构成一类特定软件可复用设计的一组相互协作的类,可以通过定义框架抽象类的应用相关的子类从而将一个框架定制为特定的应用。它规定了应用的体系结构,定义了整体结构、类和对象的分割,各部分的主要责任,类和对象怎么协作,控制流程。以便于使用者能够集中精力于应用本身。这个层次的复用导致了应用和它所基于的软件之间的反向控制,当使用工具箱时使用者写程序主体而不是调用你想复用的代码,而使用框架的时候应该复用应用的主体,写主体掉用代码,这些应用具有相似的结构,任何对框架的实质性修改都会降低框架的所带来的好处。

因为模式和框架有些类似,它们的不同是,设计模式更加抽象并且是比框架还有小的体系结构元素,框架要比设计模式更加特例化总是针对一个特定的应用领域


3.怎样选择设计模式,怎样使用设计模式

怎样选择设计模式

考虑设计模式怎么结局问题,浏览模式的意图部分,找出与使用者问题相关的模式,研究模式如何相互关联,研究目的相似的的模式,考虑设计中那些是可变的,并不是考虑什么会迫使你的设计改变而时你想要什么变化却又不会引起重新设计。

怎样使用设计模式

给出一个有效应用设计模式的的循序渐进的方法
大致浏览一遍模式要特别注意适用性部分和效果部分以确定适合你的问题
研究结构部分、参与者部分和协作部分确保类和对象是如何关联的
选择模式参与者的名字,使它们在上下文中有意义,设计模式的名字通常过于抽象而不会直接出现在应用里但是会帮助使用者哉实现中更显示的体现出模式来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值