软考架构师(9)——设计模式

全文连接:http://www.javashuo.com/article/p-ofmsztfa-gz.htmlhtml

设计模式深刻内容较多,我这里只是列举一些考试中的概念,若是你们想深刻理解一下能够参考这个大佬的博客:https://www.cnblogs.com/zuoxiaolong/category/509144.htmljava

一:概述

概念:设计模式(Design pattern)是一套被反复使用、多数人知晓的、通过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。算法

设计模式具备“适应需求变化”的优势。shell

基本原则:模块应对外扩展开放,而对修改关闭,要针对接口,而不是组合,抽象不该该依赖于细节,细节应当依赖于抽象数据库

基本分类:共23种模式 3种分类 建立型5 结构型7 行为型11编程

二:建立型5种 相公生原子

对象实例化的模式,建立型模式用于解耦对象的实例化过程。设计模式

抽象工厂模式(Abstract Factory Pattern) 

定义:(为建立一组相关或相互依赖的对象提供一个接口,并且无须指定它们的具体类。)  安全

   所谓抽象工厂模式就是提供一个接口,用于建立相关或者依赖对象的家族,而不须要明确指定具体类。他容许客户端使用抽象的接口来建立一组相关的产品,而不须要关系实际产出的具体产品是什么。这样一来,客户就能够从具体的产品中被解耦。它的优势是隔离了具体类的生成,使得客户端不须要知道什么被建立了,而缺点就在于新增新的行为会比较麻烦,由于当添加一个新的产品对象时,须要更加须要更改接口及其下全部子类。数据结构

工厂方法模式

定义:(定义一个用于建立对象的接口,让子类决定实例化哪个类。工厂方法使一个类的实例化延迟到其子类。)架构

  工厂方法模式很是符合“开闭原则”,当须要增长一个新的产品时,咱们只须要增长一个具体的产品类和与之对应的具体工厂便可,无须修改原有系统。同时在工厂方法模式中用户只须要知道生产产品的具体工厂便可,无须关系产品的建立过程,甚至连具体的产品类名称都不须要知道。虽然他很好的符合了“开闭原则”,可是因为每新增一个新产品时就须要增长两个类,这样势必会致使系统的复杂度增长。

 

生成器模式(Builder Pattern) 

定义:(将一个复杂对象的构建与它的表示分离,使得一样的构建过程能够建立不一样的表示。)

使用场景:

● 相同的方法,不一样的执行顺序,产生不一样的事件结果时,能够采用建造者模式。
● 多个部件或零件,均可以装配到一个对象中,可是产生的运行结果又不相同时,则可使用该模式。
● 产品类很是复杂,或者产品类中的调用顺序不一样产生了不一样的效能,这个时候使用建造者模式很是合适。
 
 

原型模式(Prototype Pattern)

定义:(用原型实例指定建立对象的种类,而且经过拷贝这些原型建立新的对象。)

 

单子模式 (Singleton Pattern)

定义:(确保某一个类只有一个实例,并且自行实例化并向整个系统提供这个实例。)

使用场景:

● 要求生成惟一序列号的环境;
● 在整个项目中须要一个共享访问点或共享数据,例如一个Web页面上的计数器,能够不用把每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的;
● 建立一个对象须要消耗的资源过多,如要访问IO和数据库等资源;
● 须要定义大量的静态常量和静态方法(如工具类)的环境,能够采用单例模式(固然,也能够直接声明为static的方式)。

  当系统中只须要一个实例对象或者系统中只容许一个公共访问点,除了这个公共访问点外,不能经过其余访问点访问该实例时,可使用单例模式。

  单例模式的主要优势就是节约系统资源、提升了系统效率,同时也可以严格控制客户对它的访问。也许就是由于系统中只有一个实例,这样就致使了单例类的职责太重,违背了“单一职责原则”,同时也没有抽象类,因此扩展起来有必定的困难。

 三:结构型7种 乔装打扮想外住

 把类或对象结合在一块儿造成一个更大的结构。

桥模式(Bridge Pattern)

定义:(将抽象和实现解耦,使得二者能够独立地变化。)

使用场景:

● 不但愿或不适用使用继承的场景
● 接口或抽象类不稳定的场景
● 重用性要求较高的场景
 
注意:

发现类的继承有N层时,能够考虑使用桥梁模式。桥梁模式主要考虑如何拆分抽象和实现。

 

装饰(Decorator)模式

定义:(动态地给一个对象添加一些额外的职责。就增长功能来讲,装饰模式相比生成子类更为灵活。)

使用场景:

● 须要扩展一个类的功能,或给一个类增长附加功能。
● 须要动态地给一个对象增长功能,这些功能能够再动态地撤销。
● 须要为一批的兄弟类进行改装或加装功能,固然是首选装饰模式。

 

代理模式(Proxy Pattern) 

定义:(为其余对象提供一种代理以控制对这个对象的访问。)

 

适配器模式(Adapter Pattern)

定义:(将一个类的接口变换成客户端所期待的另外一种接口,从而使本来因接口不匹配而没法在一块儿工做的两个类可以在一块儿工做。)

使用场景:

你有动机修改一个已经投产中的接口时,适配器模式多是最适合你的模式。好比系统扩展了,须要使用一个已有或新创建的类,但这个类又不符合系统的接口,怎么办?使用适配器模式,这也是咱们例子中提到的。

注意事项:

详细设计阶段不要考虑使用适配器模式,使用主要场景为扩展应用中。

 

享元模式(Flyweight Pattern)

定义:(使用共享对象可有效地支持大量的细粒度的对象。)

使用场景:

● 系统中存在大量的类似对象。
● 细粒度的对象都具有较接近的外部状态,并且内部状态与环境无关,也就是说对象没有特定身份。
● 须要缓冲池的场景。

注意:

● 享元模式是线程不安全的,只有依靠经验,在须要的地方考虑一下线程安全,在大部分场景下不用考虑。对象池中的享元对象尽可能多,多到足够知足为止。

● 性能安全:外部状态最好以java的基本类型做为标志,如String,int,能够提升效率。

 

外观模式(Facade Pattern)

定义:(要求一个子系统的外部与其内部的通讯必须经过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。)

使用场景:

● 为一个复杂的模块或子系统提供一个供外界访问的接口
● 子系统相对独立——外界对子系统的访问只要黑箱操做便可
● 预防低水平人员带来的风险扩散
注意:
●一个子系统能够有多个门面
●门面不参与子系统内的业务逻辑

 

 

组合(Composite)模式

定义:(将对象组合成树形结构以表示“部分-总体”的层次结构,使得用户对单个对象和组合对象的使用具备一致性。)

使用场景:

● 维护和展现部分-总体关系的场景,如树形菜单、文件和文件夹管理。
● 从一个总体中可以独立出部分模块或功能的场景。

注意:

只要是树形结构,就考虑使用组合模式。

 

四:行为型11种 (访问者经过观察备忘录模版状态命令中介者迭代解释职责策略)

类和对象如何交互,及划分责任和算法。

访问者模式(Visitor Pattern)

定义:(封装一些做用于某种数据结构中的各元素的操做,它能够在不改变数据结构的前提下定义做用于这些元素的新的操做。)

 

 

观察者模式(Observer Pattern)

定义:(定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则全部依赖于它的对象都会获得通知并被自动更新。)

使用场景:

● 关联行为场景。须要注意的是,关联行为是可拆分的,而不是“组合”关系。
● 事件多级触发场景。
● 跨系统的消息交换场景,如消息队列的处理机制。

注意:

● 广播链的问题

在一个观察者模式中最多出现一个对象既是观察者也是被观察者,也就是说消息最多转发一次(传递两次)。

● 异步处理问题

观察者比较多,并且处理时间比较长,采用异步处理来考虑线程安全和队列的问题。

 

 备忘录模式(Memento Pattern)

定义:(在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象以外保存这个状态。这样之后就可将该对象恢复到原先保存的状态。)

使用场景:

● 须要保存和恢复数据的相关状态场景。
● 提供一个可回滚(rollback)的操做。
● 须要监控的副本场景中。
● 数据库链接的事务管理就是用的备忘录模式。

注意:

●备忘录的生命期

●备忘录的性能

   不要在频繁创建备份的场景中使用备忘录模式(好比一个for循环中)。

 

 

模版模式(Template Method Pattern)

定义:(定义一个操做中的算法的框架,而将一些步骤延迟到子类中。使得子类能够不改变一个算法的结构便可重定义该算法的某些特定步骤。)

 

 

状态模式

定义:(当一个对象内在状态改变时容许其改变行为,这个对象看起来像改变了其类。)

使用场景:

● 行为随状态改变而改变的场景
这也是状态模式的根本出发点,例如权限设计,人员的状态不一样即便执行相同的行为结果也会不一样,在这种状况下须要考虑使用状态模式。
● 条件、分支判断语句的替代者

注意:

状态模式适用于当某个对象在它的状态发生改变时,它的行为也随着发生比较大的变化,也就是说在行为受状态约束的状况下可使用状态模式,并且使用时对象的状态最好不要超过5个。

 

命令模式

定义:(将一个请求封装成一个对象,从而让你使用不一样的请求把客户端参数化,对请求排队或者记录请求日志,能够提供命令的撤销和恢复功能。)

 

 

中介者(mediator)模式

定义:(用一个中介对象封装一系列的对象交互,中介者使各对象不须要显示地相互做用,从而使其耦合松散,并且能够独立地改变它们之间的交互。)

使用场景:

中介者模式适用于多个对象之间紧密耦合的状况,紧密耦合的标准是:在类图中出现了蜘蛛网状结构,即每一个类都与其余的类有直接的联系。

 

 

迭代器模式(Iterator Pattern)

定义:(它提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。)

 

解释器模式(Interpreter Pattern)

定义:(给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。)

使用场景:

● 重复发生的问题可使用解释器模式

● 一个简单语法须要解释的场景

 

注意:

尽可能不要在重要的模块中使用解释器模式,不然维护会是一个很大的问题。在项目中可使用shell、JRuby、Groovy等脚本语言来代替解释器模式,弥补Java编译型语言的不足。

 

职责链模式

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

 

 

 

策略模式(Strategy Pattern)

定义:(定义一组算法,将每一个算法都封装起来,而且使它们之间能够互换。)

使用场景:

● 多个类只有在算法或行为上稍有不一样的场景。

● 算法须要自由切换的场景。

● 须要屏蔽算法规则的场景。

注意事项:具体策略数量超过4个,则须要考虑使用混合模式

 

最后 加上两个 mvc 既是架构风格 也能够是 设计模式
筛选器模式 java .net 在注册访问时 经常使用的方法
一、策略 二、观察者、三、装饰 四、工厂 五、单子 六、命令 七、适配器 8模版 九、组合 十、状态
设计模式 是干啥的 ? 是 对于一类问题的通用解决办法
四要素 :模式名称、问题、解决方案、效果

 

五:软件设计原则

1.单一职责                                                                                                                                                     

一个类,只有一个引发它变化的缘由。应该只有一个职责。每个职责都是变化的一个轴线,若是一个类有一个以上的职责,这些职责就耦合在了一块儿。这会致使脆弱的设计。当一个职责发生变化时,可能会影响其它的职责。另外,多个职责耦合在一块儿,会影响复用性

简单通俗的来讲:一个类只负责一项职责。

 

遵循单一职责原的优势有:

  • 能够下降类的复杂度,一个类只负责一项职责,其逻辑确定要比负责多项职责简单的多;

  • 提升类的可读性,提升系统的可维护性;

  • 变动引发的风险下降,变动是必然的,若是单一职责原则遵照的好,当修改一个功能时,能够显著下降对其余功能的影响。

须要说明的一点是单一职责原则不仅是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则。

单一职责看似简单,实际上在实际运用过程当中,会发现真的会出现不少职责扩展的现象,这个时候采用直接违反还会方法上遵循仍是彻底遵循单一职责原则仍是取决于当前业务开发的人员的技能水平和这个需求的时间,若是技能水平不足,确定会简单的if else 去解决,不会想什么原则,直接实现功能就行了,这也是为何在不少小公司会发现代码都是业务堆起来的,固然也有好的小公司代码是写的好的,这个也是不能否认的。不过无论采用什么方式解决,心中至少要知道有几种解决方法。

 

2.里氏替换原则 (Liskov Substitution Principle)                                                                       

里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类能够出现的地方,子类必定能够出现。 LSP是继承复用的基石,只有当衍生类能够替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也可以在基类的基础上增长新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,因此里氏代换原则是对实现抽象化的具体步骤的规范。

 

 3.依赖倒置原则 (Dependence Inversion Principle)                                                       

所谓依赖倒置原则(Dependence Inversion Principle)就是要依赖于抽象,不要依赖于具体。实现开闭原则的关键是抽象化,而且从抽象化导出具体化实现,若是说开闭原则是面向对象设计的目标的话,那么依赖倒转原则就是面向对象设计的主要手段。

定义:高层模块不该该依赖低层模块,两者都应该依赖其抽象;抽象不该该依赖细节;细节应该依赖抽象。

通俗点说:要求对抽象进行编程,不要对实现进行编程,这样就下降了客户与实现模块间的耦合。

传递依赖关系有三种方式,以上的例子中使用的方法是接口传递,另外还有两种传递方式:构造方法传递和setter方法传递,相信用过Spring框架的,对依赖的传递方式必定不会陌生。

在实际编程中,咱们通常须要作到以下3点:

  • 低层模块尽可能都要有抽象类或接口,或者二者都有。【可能会被人用到的】

  • 变量的声明类型尽可能是抽象类或接口。

  • 使用继承时遵循里氏替换原则。

依赖倒置原则的核心就是要咱们面向接口编程,理解了面向接口编程,也就理解了依赖倒置。

 4.接口隔离原则 (Interface Segregation Principle)                                                                 

其原则字面的意思是:使用多个隔离的接口,比使用单个接口要好。本意下降类之间的耦合度,而设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。因此上文中屡次出现:下降依赖,下降耦合。

原定义:客户端不该该依赖它不须要的接口;一个类对另外一个类的依赖应该创建在最小的接口上。 

接口隔离原则的含义是:创建单一接口,不要创建庞大臃肿的接口,尽可能细化接口,接口中的方法尽可能少。也就是说,咱们要为各个类创建专用的接口,而不要试图去创建一个很庞大的接口供全部依赖它的类去调用。本文例子中,将一个庞大的接口变动为3个专用的接口所采用的就是接口隔离原则。在程序设计中,依赖几个专用的接口要比依赖一个综合的接口更灵活。接口是设计时对外部设定的“契约”,经过分散定义多个接口,能够预防外来变动的扩散,提升系统的灵活性和可维护性。

说到这里,不少人会觉的接口隔离原则跟以前的单一职责原则很类似,其实否则。其一,单一职责原则原注重的是职责;而接口隔离原则注重对接口依赖的隔离。其二,单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节;而接口隔离原则主要约束接口接口,主要针对抽象,针对程序总体框架的构建。

采用接口隔离原则对接口进行约束时,要注意如下几点:

  • 接口尽可能小,可是要有限度。对接口进行细化能够提升程序设计灵活性是不挣的事实,可是若是太小,则会形成接口数量过多,使设计复杂化。因此必定要适度。

  • 为依赖接口的类定制服务,只暴露给调用的类它须要的方法,它不须要的方法则隐藏起来。只有专一地为一个模块提供定制服务,才能创建最小的依赖关系。

  • 提升内聚,减小对外交互。使接口用最少的方法去完成最多的事情。

运用接口隔离原则,必定要适度,接口设计的过大或太小都很差。设计接口的时候,只有多花些时间去思考和筹划,才能准确地实践这一原则。

 

5.迪米特法则(最少知道原则) (Demeter Principle)                                                                                  

为何叫最少知道原则,就是说:一个实体应当尽可能少的与其余实体之间发生相互做用,使得系统功能模块相对独立。也就是说一个软件实体应当尽量少的与其余实体发生相互做用。这样,当一个模块修改时,就会尽可能少的影响其余的模块,扩展会相对容易,这是对软件实体之间通讯的限制,它要求限制软件实体之间通讯的宽度和深度。

定义:一个对象应该对其余对象保持最少的了解。

迪米特法则的初衷是下降类之间的耦合,因为每一个类都减小了没必要要的依赖,所以的确能够下降耦合关系。可是凡事都有度,虽然能够避免与非直接的类通讯,可是要通讯,必然会经过一个“中介”来发生联系,例如本例中,总公司就是经过分公司这个“中介”来与分公司的员工发生联系的。过度的使用迪米特原则,会产生大量这样的中介和传递类,致使系统复杂度变大。因此在采用迪米特法则时要反复权衡,既作到结构清晰,又要高内聚低耦合。

6.开闭原则(Open Close Principle)                                                                                               

开闭原则就是说对扩展开放,对修改关闭。在程序须要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。因此一句话归纳就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,须要面向接口编程。

定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭