码迷,mamicode.com
首页 > 其他好文 > 详细

模式汇总

时间:2016-06-12 03:15:37      阅读:213      评论:0      收藏:0      [点我收藏+]

标签:

参考

        设计模式之禅——里面关于模式的定义基本上都是来自于该书。
        UML类图参考

单例

        一个系统中只有一个实例。

        1,可以减少内存开支,实现数据共享。

        2,单例为静态的,生命周期与应用一样长 。处理不好,容易造成内存泄漏。

        3,单例可扩展为多例:一个系统中只有固定个数的实例。

工厂方法

        定义一个用于创建对象的接口,让子类决定具体实现哪个类。即:用一个类专门实例化客户端需要的对象。

        1,扩展性良好,添加产品类的情况下,不需要修改客户端。而且屏蔽了产品类。调用者不需要知道产品类是如何实例化的。

        2,添加对对象的控件。比如使用集合将对象缓存起来,实现对象的复用,实现享元模式。

        3,工厂方法,每一个具体产品类对应一个工厂类。

        4,简单工厂,一个工厂类可提供多个具体产品类的初始化。但这些具体产品类有一个共同的接口。android中如BitmapFactory。

抽象工厂

        为创建一组相关或相互依赖的对象提供一个接口,而且无须指定它们的具体类。即一个具体工厂类对应多个具体产品类,而且这些产品类不一定实现相同的接口。

        1,有N个产品族就有一个工厂中就有N个创建方法。有M个产品等级结构,就有M个具体工厂。

        2,扩展产品困难。扩展一个产品,所有的工厂方法都得重写。但产品等级结构扩展容易。

模板方法

        定义一个操作中算法的框架,但将算法的某些步骤延迟到子类中执行。使得子类在不改变一个算法的框架的情况下,可重定义算法的某些步骤。父类定义一个功能的主体实现部分,由子类完成其中某些特定的功能 。如AsyncTask,doInbackground()什么时候调用由父类指定,但这个方法中做什么完全由子类决定。

        1,封装了不变部分,并且可扩展可变部分。

        2,重复复杂的部分抽到父类中,而其中变化的部分由子类实现。

        3,父类也可添加勾子方法,由子类实现,从而控制具体算法中某部分是否实现。

建造者模式

        将复杂对象的构建与表现分开,使得同样的构建过程可以创建不同的对象。主要用于将复杂对象的构建与组装过程分离,使得构建与组装过程都能自由扩展。与工厂模式的不同在于:建造者着重于顺序,而工厂着重于一个部件的生产。Android中常用的AlertDialog,Notification都是使用了建造者模式。

        1,如果组装的顺序是可数的,可以添加一个Director类。

        2,一般不需要Director类,并且建造类中一般使用链式编程,即每一个方法return this。

        3,建造者模式一般用来构造复杂的对象——构造时顺序不同产生不同的效果;为某个对象的生成设置配置——避免添加一系列的setter方法,也避免了在使用时动态修改某些配置。

代理模式

        为其他对象提供一个代理,以控制对这个对象的访问。在客户端与被代理者之间添加代理层,客户端通过代理类对被代理者进行访问。

        1,添加对访问权限的控制。

        2,代理类可以处理一些逻辑,而不需要修改被代理类。如对数据的获取,一般来源于Remote与locale,可使用一个代理类对它们进行代理,在代理类中判断数据的来源,甚至可以对数据添加一些缓存数据。

        3,代理类与被代理类一般实现相同的接口。

        4,代理可分为普通代理——一个类就有一人代理类,强制代理——必须使用该类的代理类,不能直接使用该类,动态代理——没有硬编码代理类,通过Proxy.newProxyInstance指定生成一个某个接口的对象A(这个类出现在内存中,并不有.class文件),在InvocationHandler#invoke()中调用被代理类B的相应方法,同时在invoke中添加自己的处理逻辑。这样A就是B的代理类。

原型模式

        用原型实例指定创建对象的种类,并通过复制这些原型创建新的对象。简单点说就是:复制一个已有对象,生成一个新的对象(相当于复制文件,复制出来的文件与原文件是两个文件)。

        1,复制分为浅复制与深复制。原型对象中属性值是什么,新对象也具有相同的属性值。如果是引用数据类型,那么新对象与原型对象指向会指向同一个地方。深复制就是将属性指向的对象也进行复制。

        2,如果一系列对象具有一些相同的属性值,可以new一个原型对象,通过clone复制成一个新对象,对新对象进行个性的属性修改,就可以得到不同的对象。使用原型模式先产生一个包含大量共有信息的类,然后通过复制复本,修正细节信息,建立一个完整的个性对象。

        3,原型模式与final是死敌,使用final对象,则无法使用clone。

        4,原型模式是直接在内存中通过二进制流进行复制,比new一个对象的性能好很多,并且可以逃避构造函数的约束。复制得到的对象,不会调用构造函数

中介者模式

        用中介者封装一系列对象的交互,中介者使各个对象之间不能显式的交互,从而使其耦合松散,而且可以独立地改变它们之间的交互。

        多个对象之间相互依赖,使它们的类图成网状,可以添加一个中介者,隔离各个类之间的依赖——使它们之间多对多的关系转变成一对多(都依赖于中介者,而不依赖于其它对象),而与其它对象的交互完全由中介者控制。可以将中介者想像成服务器,多个app就是终端,它们都是通过服务器才互相交流的,并没有直接交流。

        Android中,MVP就是中介者的体现(p为中介者,隔离了M与V的联系,它们的交互也完全依赖于P),甚至平时使用的一个界面中控件之间的作用也是中介者(如点击一个btn,清除掉edt中的文字,那么此时activity或fragment就是中介者)。

        1,隔离类之间的复杂依赖,对网状结构的依赖进行解耦,由多对多变成一对多。

        2,一个类必然会与其余的类产生依赖,如果这种依赖非常复杂(类图成网状)可以使用中介者模式进行解耦,如果不复杂就不要使用中介者——使用的话会导致结构变得更复杂。

        3,每一个类直接与中介者联系,不直接由其它类交互,与其它类的联系也完全交由中介者控制。这样,这些类只需要完全自己的部分,至于自己的操作会对其它类产生哪些影响完全不属于这个类应该考虑的,这是由中介者考虑的。

        4,由于中介者要处理的逻辑比较多,可能会导致中介者的臃肿,此时可将中介者拆分。

命令模式

        将客户端的请求封装成对象,从而使用不同的请求把客户端参数化,对请求可以排队或者记录请求日志,从而可以提供请求的撤销和恢复功能在发起者与接收者之间添加一个命令层,避免发起者直接与处理者交互。处理方法就是将发起者的请求封装成一个类(命令),并由一个管理类管理所有的命令(以方便实现撤销功能),发起者只需要调用命令中某个方法,而在该方法中,命令会调用真正的处理者进行处理。这样就避免了发起者与处理者直接交互。例如实现涂鸦,如果想实现撤销本次绘制,使用命令模式是非常方便的。

        1,将所有的请求都封装成一个对象,一个请求对象与初始请求完全无关的生命周期。请求对象中,实现了请求的实现,并记录着客户端请求的参数。

        2,它将请求者与处理者分离,方便对两者进行扩展。

        3,如果请求过多,会导致请求类的严重膨胀。

        4,实现反悔命令,需要一个执行者。执行者内部记录所有的请求记录,反悔即是删除其中记录的最新一条请求,并代理执行所有的请求的操作。

责任链模式

        使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些接收者连成一条链,并沿着该链将请求传递,直到有接收者处理这个请求为止。android中,touch事件的处理就是典型的责任链模式;对于数据库的升级也可以使用责任链模式——每一个版本升级时进行的操作就是一个节点,比对这个节点对应的数据库版本号以及app中数据库的版本号,如果前者较大,那么就需要执行升级方法,处理完成之后需要将请求传递到下一个节点。

        1,对某一处请求,有多个接收者(其中只有一部分是能处理该请求的),将这些接收者串成一个链,并将请求从链首到链尾进行传递,具体的接收者自己判断是否能处理该请求。走到链结束,或者处理结束。

        2,将请求者与处理者隔离,请求者并不知道是哪些处理者处理了自己的请求。也避免了请求者自己判断哪些处理者符合自己的条件。

        3,如果链条过长,处理一个请求时需要遍历所有的节点,对性能有一定影响。

        4,一般链表的形成不由客户端控制,即该节点的下一个节点是哪个,请求者不应该知道。请求者拿到的应该是链表的头节点。

装饰模式

        动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式相比生成子类更为灵活。将被装饰类做为装饰类的成员变量,用装饰类中的方法为被装饰类进行增强。

        1,代理类偏重于对被代理类的访问控制,而装饰却偏重于对被装饰类的功能的增强。但两者的表现形式上没有多大的区别。

        2,如果装饰层次过多,容易导致修改复杂。所以应尽量减少对多层装饰的使用。

        3,它是对继承的一个有力补充——通过组合代替继承。

        4,必须有一个最基本的,最核心的最原始的接口或抽象类,装饰者和被装饰者都必须是它的子类。

策略模式

        定义一组算法,将每一个算法封装起来,并且使它们之间可以互换。例如对于排序来说,它有好多种方法:堆,希尔,快速,插入,选择,基数,计数,归并,冒泡等,这些排序算法是具有相同的逻辑的。首先输入一个序列,其次进行操作,再次返回操作之后的结果。而不同的排序算法,操作时的实现方式是不同的,但它们又是可互相替换的。所以可以将它们封装成策略类,在使用时使用不同的策略类进行排序。

        1,策略类的着重点在于各个类之间的替换,而代理类却不是替换,而是一种对另一种的代理。

        2,策略模式中的场景类不需要与策略类实现相同的接口或继承于同样的抽象类,但代理类却需要。

        3,导致类的臃肿,一种策略就需要一个单独的策略类。

        4,客户端必须知道所有的策略类,也就是说策略类对客户端不是透明的。

适配器模式

        将一个类的接口变换成客户端需要的另一种接口,从而使原末因接口不匹配而无法在一起工作的两个类能在一起工作。android中ListView的Adapter,它将客户端已有的数据集合(如List)变换成ListView需要一View集合,从而能正常显示。

        1,可以让两个无关的类能一起正常工作。

        2,已有的、已投入使用中的类不应该进行个性,需要通过适配器模式转换成当前所需要的。

        3,它是一种补救方法,是为了扩展应用,而不是为了解决开发阶段类不兼容的问题。

迭代器模式

        它提供一种方法访问一个容器内部的各个元素,而不需要暴露该对象的内部细节。JAVA中的Iterable与Iterator都是为迭代器模式设置的类。

        1,Iterable该类可进行迭代。Iterator具体的迭代器。

组合模式

        将对象组合成树形结构以表示”部分-整体“的层次结构,使得用户对单个对象和组合对象使用具有一致性。组合模式将组合对象与单个对象统一看待。Android中View与ViewGroup就是组合模式。

        1,组合对象,内部包含多个单个对象组成的对象。如树结构中的叶子节点,它是单个对象;而它们的父节点就是组合对象,一个组合对象是由若干个对象组成的。并且组合对象与单个对象拥有相同的父类。

        2,树形结构的关系时,适合采用组合对象。

        3,分为安全模式与透明模式。安全模式:单个对象只具有单个对象该有的方法,而不应该具有组合对象才具有的方法(如add单个对象等),android中的View与ViewGroup就是采用了这个模式;透明模式:单个对象也应该具有组合对象独有的方法,这样可以使组合对象与单个对象完全相同,只不过在add等方法中单个对象一般需要扔一个UnsupportedOperationException。

观察者模式

        定义对象间一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。Java中的Observable与Observer就是实现观察者的系统类。

        1,被观察者通知观察者是,默认是顺序的,因此一个观察者卡壳必然会影响其后面的所有观察者。

        2,应严防观察链的出现。一个观察者模式中,最多出现一个对象即是观察者又是被观察者,也就是说消息最多只能转发一次。

门面模式

        又称外观模式。要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供了一个高层次的接口,使得子系统更易于使用。它的精髓在于封装,将子系统的功能通过一个类展示给调用者,而调用者只需要了解这一个类即可,减少学习成本,降低学习难度。比如使用第三方sdk时,一般都是通过一个类进行的。如使用WX的sdk,登录、分享等功能都是通过WXApi这个类完成的。这就是门面模式——将sdk的功能点通过一个类提供给外界使用。

        1,门面类是外界访问子系统的唯一通道,无论子系统多么复杂、烦乱,都不影响外界类,减少了不同系统之间的依赖。

        2,当子系统比较独立时,宜采用门面模式,为外界提供一个访问类。外界对于子系统的访问全部是暗箱操作。

        3,如果门面类非常庞大,可以拆分成多个。

        4,如果子系统进行修改,可能会需要跟着修改门面类。不符合开闭原则。

        5,门面类不能参与子系统的逻辑,它只是外界发起的请求的一个转发者。

备忘录模式

        在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。在一定时机下,保存一个对象中一部分或全部状态,并将这些状态单独形成一个类,在恢复时将这些类中存储的信息还原到原对象中。类似于后悔药。其核心为回滚、保存、恢复

        1,可采用原型模式,使用clone()复制成自身的一个副本,并保存该副本,还原时将副本中的信息设置到要还原的对象中。但,原型模式涉及到深复制与浅复制,因此它只适合状态比较简单的对象。

        2,可以提供一个类似回滚的操作,可用于保存和恢复。

        3,需要一个备忘录管理类用于管理生成的备忘录对象。例如可为各个备忘录设置一个tag,并根据tag不同恢复到不同的备忘状态。类似于android中的Canvas#save()与Canvas#restore()。

        4,生成的备忘录对象除了发起人(即生成备忘录对象的对象),绝对不能直接被外界操作,也绝对不能修改,以免影响到当前保存的状态。所以备忘录类应该是发起类的内部类。

        5,备忘录类为发起类的内部类,那么对于管理类有两种处理方式(主要目的是避免通过管理类获取到备忘录类,从而进行操作)。其一,由发起类操作管理类,外界也无法接触管理类。其二,备忘录类实现一个空接口,而管理类内部使用该接口而不是直接使用备忘录类自身,这样外界即使接触到管理类,获取的也是一个空接口,也无法对备忘录对象进行操作。

        6,宽接口,定义类的实际业务方法。窄接口,内部什么都不定义,只是为了让外面使用,从而可以避免外界修改该类的数据。

访问者模式

        封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。添加一个类,由该类根据需求从被访问者中获取所需要的数据,而不必修改原类。

        1,一个对象结构(就是一个对象容器)中包含不同的对象——它们具有不同的接口,是毫无关联的——想要对这些对象进行依赖于具体对象的操作,有两种方式。其一、迭代器,通过instance of判断具体是哪种类型。其二,使用访问者模式,将不同类的操作完全封装在一具访问者中,遍历时只需要类接收访问者即可。

        2,需要对一个对象结构中的对象进行很多不同并且不相关的操作,可以使用访问者,这些可以避免因为这些操作而污染了原来的对象。

        3,观察者模式是一个被动型的,被观察的东西发生变化才会触动观察者。访问者模式是一个主动型的,访问者根据自己的需要获取数据。

        4,访问者必须完全了解它要访问的对象,而观察者却不需要。

状态模式

        当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。状态模式中行为由状态来决定,不同的状态有不同的行为,状态模式中不同的状态是平行的,不可替换的。状态模式把对象的行为包装在不同的状态对象里,每一个状态对象都有一个共同的抽象状态基类。

        1,一个对象的行为取决于它的状态,并且必须在运行时根据状态改变它的行为。

        2,代码中包含大量分支、判断语句,可用状态模式代替。

        3,每一个状态放入一个独立的状态对象中,这一对象不依赖于其它状态对象,并且它需要处理在该状态下应该完成的任务以及决定是否切换到其他状态。

        4,不成文的规定:环境类中把状态对象声明为静态变量,有几个状态就声明几个;环境类具有抽象状态类所定义的所有行为,具体的执行使用当前的状态中相应的方法。

解析器模式

        给定一门语言,定义它的方法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。简单理解就是一定的规则翻译某一个句子,如数学中的a+b+c-d,解释器就需要按照数学的规则来翻译该句子,并执行相应的操作。

        1,终结符号,操作数。非终结符号,代表一种操作,如上面的+,-号,其两边总能找到终结符号。

        2,解释器的主要作用就是定义非终结符号对两边操作数的运算方法。当然还有对应操作数的解释器,它直接返回操作数即可。

        3,解释器容易扩展,新定义一个种操作,只需要新添加一个解释器即可。但,这也容易造成类的膨胀。

享元模式

        使用共享对象可有效支持大量的细粒度对象。重复利用已创建过的对象,避免大量创建对象消耗内存。如android中的Message。

        1,使用享元模式,需要注意线程完全。因为对象是共享的,所以有可能多个线程共享同一个对象,导致数据混乱。

桥梁模式

        将抽象与实现解耦,使两者可独立变化。它也是用来代替继承的。

        1,将类中易变的部分抽取出来,以一单独类实现该功能。并采用聚合的方式,将新添加的类聚合到原类中,并在相应方法中调用新添加类的相应方法,以完成旧类的功能 。

        2,有多上维度上的变化,将这些维度单独抽象实现,并通过组合的方式完成一个具体的类。


模式汇总

标签:

原文地址:http://blog.csdn.net/u010410408/article/details/51601206

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!