设计模式总结

   大设计模式读后总结

1、概述

在网上看过一个对面向对象和面向过程两者之间的比喻,我觉得很是恰当。说面向过程像一份蛋炒饭而面向对象像一份盖浇饭。蛋炒饭的好处就是入味均匀,吃起来香。如果恰巧你不爱吃鸡蛋,只爱吃青菜的话,那么唯一的办法就是全部倒掉,重新做一份青菜炒饭了。盖浇饭就没这么多麻烦,你只需要把上面的盖菜拨掉,更换一份盖菜就可以了。盖浇饭的缺点是入味不均,可能没有蛋炒饭那么香。到底是蛋炒饭好还是盖浇饭好呢?其实这类问题都很难回答,非要比个上下高低的话,就必须设定一个场景,否则只能说是各有所长。那么从饭馆角度来讲的话,做盖浇饭显然比蛋炒饭更有优势,他可以组合出来任意多的组合,而且不会浪费。对于大型的软件开发的话我觉得面向对象很有必要,因为面向对象的可拓展性、可维护性大大优于面向过程。

2、设计模式原则

2.1、单一职责原则

所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。

  2.2、开放封闭原则

关于开放封闭原则,其核心的思想是:软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。因此,开放封闭原则主要体现在两个方面:对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。

2.3、依赖倒转原则

高层模块不应该依赖低层模块。两个都应该依赖抽象。抽象不应该依赖细节。细节应该依赖抽象

2.4、里氏代换原则

    子类型必须能够替换掉它们的父类型。一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且察觉不出父类对象和子类对象的区别。也就是说,在软件里面,把父类都替换成它的子类,程序的行为没有变化

2.5、迪米特法则(最少知识原则

   如果两个类不必彼此直接通信,那么这两个类就不应当发生直接相互作用。如果其中一个类需要另外一个类的某一个放阿飞,可以通过第三者转发这个调用。其原则就是强调类之间的耦合越弱,越有利复用。一个处于若耦合的类被修改,不会对有关系的类造成波及。

2.6、合成、聚合复用原则

   尽量使用合成/聚合,尽量不要使用类集成。优先使用对象的合成/聚合将有助于保持每个类被封装,并集中在单个任务熵。这样类和类的集成层次会保持较小的规模,并且不太可能增长成不控制的庞然大物。

3、设计模式详述

 3.1、策略模式、简单工厂

 定义:策略模式是对算法的包装,是把使用算法的责任和算法本身分割开来,委派给不同的对象管理。策略模式通常把一个系列的算法包装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是:“准备一组算法,并将每一个算法封装起来,使得它们可以互换”

类图:

简单工厂

https://i-blog.csdnimg.cn/blog_migrate/0106266576e22ac8460c551950b2b980.png

策略模式:

 https://i-blog.csdnimg.cn/blog_migrate/b4bd924f32b089a3cb783975900dd314.png

优点:策略模式;算法可以自由切换,避免使用过多的条件判断,扩展性良好。简单工厂;模块清晰,每个模块各司其职,分工明确,代码就实现最渐层意义上的维护。

缺点:策略模式:策略类会增多,所有策略都要对外暴露。简单工厂:当新增功能时需要新添加一个类,同事需要在factory中改动switch里面的代码,破坏了封闭开发原则。

应用场景:当一个系统中有许多类,它们之间的区别仅在于它们的行为,希望动态地让一个对象在许多行为中选择一种行为时;当一个系统需要动态地在几种算法中选择一种时; 当一个对象有很多的行为,不想使用多重的条件选择语句来选择使用哪个行为时。

二者区别:策略模式和简单工厂模式看起来非常相似,都是通过多态来实现不同子类的选取,这种思想应该是从程序的整体来看得出的。如果从使用这两种模式的角度来看的话,我们会发现在简单工厂模式中我们只需要传递相应的条件就能得到想要的一个对象,然后通过这个对象实现算法的操作。而策略模式,使用时必须首先创建一个想使用的类对象,然后将该对象最为参数传递进去,通过该对象调用不同的算法。在简单工厂模式中实现了通过条件选取一个类去实例化对象,策略模式则将选取相应对象的工作交给模式的使用者,它本身不去做选取工作。结合上面的代码和下面的释义不难看出,其实两个的差别很微妙,Factory是直接创建具体的对象并用该对象去执行相应的动作,而Context将这个操作给了Context类,没有创建具体的对象,实现的代码的进一步封装,客户端代码并不需要知道具体的实现过程

3.2、装饰模式

定义:装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象

优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能

缺点:多层装饰比较复杂

应用场景1、扩展一个类的功能。 2、动态增加功能,动态撤销。

类图:

https://i-blog.csdnimg.cn/blog_migrate/e220c2421ec91ce32597b7954227f921.png

3.3、代理模式

定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。

优点:1、职责清晰。2、高扩展性。 3、智能化

缺点:1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

应用场景按职责来划分,通常有以下使用场景: 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理

类图

http://ww1.sinaimg.cn/large/006rMFVegy1fdpnfxbh3oj30j60ayglq.jpg

 

3.4、工厂方法模式

定义:定义一个创建对象的工厂接口,让子类决定实例化哪一个类,将实际创建工作推迟到子类当中

有点:创建对象的接口,让子类决定具体实例化的对象,把简单的内部逻辑判断移到了客户端。工厂方法模式克服了简单工厂所违背的开闭原则的缺点,又保持了封装对象创建过程的优点。扩展性高,想要增加一个产品,只要扩展一个工厂类就可以

缺点:次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事

应用场景:当一个类不知道它所需要的对象的类时 在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可;当一个类希望通过其子类来指定创建对象时 在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。

类图:

 

3.5、模板方法模式

定义:定义一个操作中的算法的骨架,而将一些步骤延迟到了子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤

优点:提高代码复用性 ,将相同部分的代码放在抽象的父类中;提高了拓展性 ,将不同的代码放入不同的子类中,通过对子类的扩展增加新的行为;实现了反向控制 通过一个父类调用其子类的操作,通过对子类的扩展增加新的行为,实现了反向控制 & 符合“开闭原则”

缺点:引入了抽象类,每一个不同的实现都需要一个子类来实现,导致类的个数增加,从而增加了系统实现的复杂度

应用场景:一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现;各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复;控制子类的扩展。

类图:https://i-blog.csdnimg.cn/blog_migrate/5f52742efbbaaa40ffb4b649dfac472f.png

 

3.6、外观模式

定义:为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。简单来说,客户端需要调用一个特别复杂的子系统中的多个接口,如果直接调用逻辑处理起来会非常复杂,而且不便于系统扩展。外观模式把这个复杂的子系统统一起来,提供几个高层接口,以备客户端进行调用。通俗来说是:子系统是一个黑匣子,提供若干个透明接口以备调用。

优点:外观模式对客户端屏蔽了子系统组件,从而简化了接口,减少了客户端处理的对象数目并使子系统的使用更加简单。外观模式实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件是紧耦合的。松耦合使得子系统的组件变化不会影响到它的客户端。

缺点:不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。

应用场景:1、为复杂的模块或子系统提供外界访问的模块。 2、子系统相对独立。 3、预防低水平人员带来的风险

类图:

https://i-blog.csdnimg.cn/blog_migrate/ea1d6a92cf6436f9c771654190a87905.png

 

3.7、建造者模式

定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

优点:使用建造者模式可以使客户端不必知道产品内部组成的细节。具体的建造者类之间是相互独立的,对系统的扩展非常有利,由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响

缺点:产生多余的Build对象以及Dirextor类,消耗内存,对象的构造过程暴露。

应用场景:当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。 相同的方法,不同的执行顺序,产生不同的事件结果时。 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时。 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能。 创建一些复杂的对象时,这些对象的内部组成构件间的建造顺序是稳定的,但是对象的内部组成构件面临着复杂的变化。 当构造一个对象需要很多参数或者参数的个数和类型不固定的情况下

 

类图:

https://i-blog.csdnimg.cn/blog_migrate/a1fa5a067e616b6bd55ccc3d5547d252.png

 

3.8、观察者模式

定义:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。此种模式通常被用来实时事件处理系统。其中两个重要对象是观察者和主题,要想主题对象发生改变时,能通知到所有观察者角色,则自然主题角色必须引用观察者,从而完成观察模式。

缺点:第一、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。第二、如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察者模式是要特别注意这一点。第三、如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。第四、虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的

应用场景:对一个对象状态的更新,需要其他对象同步更新,而且其他对象的数量动态可变。  对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。

类图:https://i-blog.csdnimg.cn/blog_migrate/869765518d8fdaa7d53698e2cfe85394.png

3.9、抽象工厂模式

定义:是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象

优点:需求改变时改动最小;具体的创建实例过程与客户端分离,客户端通过抽象接口操作实例,产品的具体类名也被具体工厂的实现分离,不出现在客户端代码中(客户端只知道有一个抽象工厂,一个抽象的Engine和一个抽象的Tyre

缺点:新增功能时,比如火车和飞机都有窗户,那就要增加3个类,还要修改2个具体的工厂类。

应用场景:

类图:

https://i-blog.csdnimg.cn/blog_migrate/0152a2de12f7e4bfb38dc0bde017b001.png

 

3.10、状态模式

定义:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化

优点: 1、封装了转换规则。 2、枚举可能的状态,在枚举状态之前需要确定状态种类。 3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。 4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。 5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

缺点:1、状态模式的使用必然会增加系统类和对象的个数。 2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。 3、状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。

应用场景:1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。2.一个操作中含有庞大的多分支结构,并且这些分支决定于对象的状态

类图

https://i-blog.csdnimg.cn/blog_migrate/9990342b27e5a07a3ae3d0a12bc650c9.png

 

 

3.11、适配器模式

定义:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。适配器模式好比一个电源适配器,生活中房间内的电压是220v,但是你的很多用电器就不是220v,比如电脑、手机等等,这是需要电源适配器来调节电压,使用电源适配器充电的过程就相当于适配器模式

优点:1、可以让任何两个没有关联的类一起运行。 2、提高了类的复用。 3、增加了类的透明度。 4、灵活性好。

缺点:过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。 2.由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。

应用场景:有动机地修改一个正常运行的系统的接口,这时应该考虑使用适配器模式

类图:

https://i-blog.csdnimg.cn/blog_migrate/69dd77383748cfbaa2f9b53f86b52cce.png

3.12、组合模式

定义:又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式

优点:1、高层模块调用简单。 2、节点自由增加。

缺点:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。

应用场景需要表示一个对象整体和部分的层次结构,用户希望忽略组合对象和单个对象的不同,一致的处理组合对象和单个对象。

类图:

https://i-blog.csdnimg.cn/blog_migrate/c47f9b11f602aafe473fb7dbae3e14b0.png

 

 

3.13 、访问者模式

定义:我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作

优点:访问者模式使得添加新的操作变得容易。如果一些操作依赖于一个复杂的结构对象的话,那么一般而言,添加新的操作会变得很复杂。而使用访问者模式,增加新的操作就意味着添加一个新的访问者类。因此,使得添加新的操作变得容易

缺点:增加新的元素类变得困难。每增加一个新的元素意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中添加相应的具体操作。

场景:对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。 2、需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。

类图:

https://i-blog.csdnimg.cn/blog_migrate/eb8a26c48bc0b01069c87d7b95d592fe.png

 

3.14、单例模式

定义:保证一个类仅有一个实例,并提供一个全局访问点

优点:在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。 2、避免对资源的多重占用(比如写文件操作)

缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

应用场景:要求生产唯一序列号。 2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。 3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。

类图:

http://static.oschina.net/uploads/space/2015/0619/120556_SZyi_1989321.jpeg

 

3.15、桥接模式

定义:是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类。这两种类型的类可被结构化改变而互不影响。

优点:1、抽象和实现的分离。 2、优秀的扩展能力。 3、实现细节对客户透明。

缺点:桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。

应用场景: 1、如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。 2、对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。 3、一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。

类图:

https://i-blog.csdnimg.cn/blog_migrate/0b461cb1b43840e0b15923eb7fef0e5b.png

 

3.16、命令模式

定义:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销操作

优点:1、降低了系统耦合度。 2、新的命令可以很容易添加到系统中去。

缺点:使用命令模式可能会导致某些系统有过多的具体命令类。

应用场景:基本上能表现其优点的地方都可以使用命令模式。

类图:

https://i-blog.csdnimg.cn/blog_migrate/7e5faee421da1f9b4e077aec58072f6f.png

 

3.17、职责模式

定义:使得多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止

优点:降低耦合度。它将请求的发送者和接收者解耦。 2、简化了对象。使得对象不需要知道链的结构。 3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很方便。

缺点:1、不能保证请求一定被接收。 2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。 3、可能不容易观察运行时的特征,有碍于除错。

应用场景: 1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。 2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。 3、可动态指定一组对象处理请求。

类图:

https://i-blog.csdnimg.cn/blog_migrate/910cf07377a532134b24b24cabaf3143.png

3.18、中介者模式

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

优点:将各个对象类解耦,同时简化对象之间的关系,使系统变为松耦合, 系统更加灵活,各个对象独立而易于复用。

缺点:中介者模式中,中介者承担了较大的责任,一旦中介者出现问题,整个系统都会受到较大的影响, 新增一个对象类,需要修改抽象中介者和具体中介者类

应用场景:中介者模式一般应用于一组对象以定义良好但是复杂的方式进行通信的场合,及想定制一个分布在多个类中的行为,而又不想生成太多的子类的场合

类图:

https://i-blog.csdnimg.cn/blog_migrate/0d688b35d9d9a1b558744bd35446b080.png

3.19、亨元模式

定义:主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。

优点:大大减少对象的创建,降低系统的内存,使效率提高。

缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。

应用场景:统中需要大量的细粒度对象,同时这些对象耗费大量的内存,并且对象的状态大部分可以外部化,此时使用享元模式是没有错的。

类图:

https://i-blog.csdnimg.cn/blog_migrate/9919f45ea217a38a6a27b0766f91cee5.png

3.20、解释器模式

定义:提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文

优点:1、可扩展性比较好,灵活。 2、增加了新的解释表达式的方式。 3、易于实现简单文法。

缺点: 1、可利用场景比较少。 2、对于复杂的文法比较难维护。 3、解释器模式会引起类膨胀。 4、解释器模式采用递归调用方法

应用场景:1、可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。 2、一些重复出现的问题可以用一种简单的语言来进行表达。 

类图:

https://i-blog.csdnimg.cn/blog_migrate/2b754f4b15793c43a2b4f53f01db5fa5.png

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值