设计模式简述

一、设计模式的诞生与发展

1、(Pattern)模式起源于建筑业而非软件业。它是总结前人的经验的总结,为后人设计开发基于面向对象的软件提供指导方针和成熟·的解决方案。

2、软件模式可以认为是对软件开发者一特定“问题”的“揭发”的某种统一表示。软件模式的基本结构由4个部分构成,即问题描述,前提条件,解法和效果

3在软件设计模式领域,目前研究最为深入的时设计模式,狭义的设计模式就是指GOF的书中包含的23种经典的设计模式。事实上,设计模式不仅仅只有23种,越来越多的新模式不断诞生并得以广泛应用。



二、设计模式的定义与分类

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

GoF对设计模式的定义:

设计模式是在特定环境下为解决某一通用软件设计问题提供的一套定制的解决方案,该方案藐视了对象和类之间的相互作用。
Design patterns are descriptions of communicating objects and classes that are customized to solve a general design problem in a particular context.

三、设计模式的分类:

1、创建型模式:单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。

2、结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。

3、行为型模式:模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。


四、GoF设计模式简介

表一      GoF23种模式一览表




表二      GoF的23种模式的简要说明




表三     GoF的23种模式的简要说明序



五、面向对象设计的原则

软件的可维护性(Maintainability)和可复用性(Reusability)是两种非常重要的用于衡量软件质量的质量属性,软件的可维护性是指软件能够被理解,改正,适应即扩展的难易程度,软件的可复用性是指软件能够被重复使用的难易程度。

面向对象设计的目标之一在于支持可维护性复用,一方面需要实现设计方案或者源代码的复用,另一方面要确保系统能够易于扩展和修改,具有良好的可维护性。

下述7个面向对象设计原则:

1、单一职责原则(Single Responsibility Principle)
    单一职责原则的核心精神是:一个类,或者一个接口,最好只做一件事情,当发生变化时,他只能受到单一的影响;因为职责过多,可能引起变化的原因将会很多,这样导致职责和功能上的依赖,将严重影响其内聚性和耦合度,混乱由此而生。
    单一职责的原则在现实生活中早就实践于现代公司体制与工业生产上,如公司的各个部门职责分明相互独立,生产流水线的某一环节只需关注上螺丝,而另一环节只做零件组装等等;这一原则使庞大的系统组合起来还能各司其职,井井有条,即使某个部门、某个环节出了问题或需要改动,你只需去动那个要变动的地方即可,从而避免因职责功能不明而导致不必要的的混乱。同样,程序代码的设计也是如此,功能和职责单一化也是衡量代码优良的一个标准;交杂不清的职责和功能将使得代码看起来特别别混乱、别扭且一发而动全身,更严重的是在日后的维护中你得花更多的时间去理清他的逻辑,并且这地方的变动几乎是必然引起让人头痛的BUG,你将花费更多的精力,承担更多的风险! 在代码工程的实施中,遵循单一职责原则将会带来诸多好处:类的复杂性将降低,简单明细的代码将使可读性将大大提高,自然而然可维护性亦将同步提高,可维护性提高将预示着因变更引起的风险会大大降低,最重要的前边的好处将会是你工作轻松愉悦、思路清晰、远离脑爆头大……专注即高效,单一既轻松,人事皆如此。

2、里氏替换原则(Liskov Substitution Principle):
    里氏替换原则的核心精神是:在使用基类的的地方可以任意使用其子类,能保证子类完美替换基类;这一精神其实是对继承机制约束规范的体现。在父类和子类的具体实现中,严格控制继承层次中的关系特征,以保证用子类替换基类时,程序行为不发生问题,且能正常进行下去。
    里氏替换原则主要发力点是继承基础上的抽象和多态,具体就是子类必须实现父类的方法,是重写;这里要注意重写(Override)与重载(Overload)的区分,即使参数的数据范围发生变化,也能将重写变成重载!而你原本只是想把所继承的方法完善的具体点儿!如果是这样的话绝对会引起以后业务逻辑的混乱。
    里氏替换原则是关于继承机制的设计原则,违反里氏替换原则将会使继承变的一塌糊涂;而遵循里氏替换原则能够保证系统具有良好的的拓展性,我们可以随时根据需要增改不同的子类,这将大大增强程序的健壮性,让版本的升级可以做到非常好的兼容;同时基于多态的抽象机制,能够很好的减少代码冗余,避免运行期的类型判别等;而在项目的实施中不同的子类对应着不同的业务,使用父类做参数,不同子类可以轮番上阵,必然强大!
 
3、接口隔离原则(Interface Segregation Principle):
    接口隔离原则的核心精神是:尽量使用多个专门的单一的小接口,避免庞大的总接口;专业点的说法是类间的依赖关系尽量建立在最小的接口上。接口尽量的小,但是小不是说一个接口一个方法,小也要不违背单一职责原则;接口应该严格体现内聚性,尽可能的少公布public方法,在开发中不能让功能繁琐的大接口出现;一个类对另一个类的依赖应该建立在最小的接口上,不能强迫与之无关的方法,否则将会造成接口污染。遵循接口隔离原则将使接口有效的将细节和抽象隔离,体现了对抽象编程的一切优点,接口隔离强调接口的单一性。而大接口因强制要求实现类完成它所有的并非必须的方法、属性等,从而造成严重的设计浪费,对以后的维护和改动带来难以衡量的困难,对“接口”这个概念造成极大的侮辱。
    但在现实中,如何把握接口越小越好,这个度很难界定,颗粒度小固然灵活,但同时会造成结构的复杂化,以下有几个把握规则可以参考:一个接口只服务于一个子模块或业务逻辑,服务定制;通过业务逻辑压缩接口中的public方法,让接口看起来精悍;已经被污染了的接口,尽量修改,如果变更风险太大,则用适配器模式进行转化处理;根据具体的业务,深入了解逻辑,用心感知去控制设计思路。
         具体如何实施接口隔离,主要有两种方法:1、委托分离,通过增加一个新的接口类型来委托客户的请求,隔离客户和接口的直接依赖,注意这同时也会增加系统的开销;2多重继承分离,通过接口的多重继承来实现客户的需求,这种方式相对较好。具体的使用,视情况而定。
         怎么准确的实践接口隔离原则呢?有一本书上写得非常好:实践、经验和领悟。

4、迪米特法则(Low Of Demeter):

迪米特法则也叫做做最少知识原则,其核心精神是:不和陌生人说话,通俗之意是一个对象对自己需要耦合关联调用的类应该知道的更少。这样会导致类之间的耦合度降低,每个类都尽量减少对其他类的依赖,因此,这也很容易使得系统的功能模块相互独立,之间不存在很强的依赖关系。
         迪米特法则很纯情、比较保守,不希望和其他的类建立直接的接触;如果真的需要交互关系,也是希望通过自己比较熟的中间类来传达信息。因此,在迪米特法则的实际应用中可能会导致大量的中介类。
         迪米特法则的核心就是解耦,弱耦合能使类的复用率提高,在实际中这个解耦是有限度的解耦,不能因法则而法则,应权衡利弊而为之。

5、开闭原则(Open Close Principle):
         开放封闭原则,简称开闭原则。开闭原则是面向对象设计中“可复用设计”的基石原则,是面向对象设计中最重要的原则之一,属于“易筋经”级别的,诸如里氏替换啦,接口隔离啦、依赖倒置啦,都可以看做是开闭原则的实现;在面向对象设计中,抽象类和接口,即是因开闭而生,应开闭而存!
         开闭开闭,开放封闭。开放的是拓展,封闭的是修改,即降低耦合,封装变化的集中展现。开放扩展,则意味着当有新的或变化的需求时,可以通过对现有代码的拓展来实现,而不需要该变原有程序的结构与内容;封闭修改,指的是程序设计一旦完成,其预定功能即按照既定独立工作,在不可对其做修改操作(太绝对了、太完美了!)开闭原则的核心思想就是抽象编程,而不是对具体,因为抽象是相对稳定的,再说了我们还有接口(好多地方接口和抽象类都放一块儿说了)。让类依赖于固定的抽象对象,即可以达到封闭修改的目的;而通过面向对象的继承和多态机制,又可以实现对抽象类的继承,通过复写其方法来改变固有的行为操作,也可以实现新的拓展方法,即可以达到开放的目的。
         归根究底,开闭原则就是“万变不离其宗”;变,即变的是需求,宗,既是系统强大稳定的基础核心;开放封闭,既可以通过开放拓展满足需求的变化,又可以通过封装而使系统稳定。开闭原则,实乃程序设计心法,金刚般若波罗蜜!

6、依赖倒置原则(Dependence Inversion Principle):
         依赖倒置原则,重要的三层含义:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。其核心思想是:依赖于抽象。
         关于“倒置”这个词。准确的讲,这是因为传统的软件开发方法,如结构化的分析和设计,倾向于创建高层模块依赖于低层模块、抽象依赖于具体的软件结构。在实际上,这些方法的目标之一就是去定义描述上层模块如何调用低层模块的子程序层次结构。所以,相对于传统的过程化的方法通常所产生的那种依赖结构,一个设计良好的面向对象的程序中的依赖结构就是“被倒置”的。
         在系统代码的实现中,依赖关系一定会存在于类与类、模块与模块之间。当两个模块之间存在紧密的耦合关系时,最好的方法就是分离接口和实现:在依赖之间定义一个抽象的接口使得高层模块调用接口,而底层模块实现接口的定义,以此来有效控制耦合关系,达到依赖于抽象的设计目标抽象的稳定性决定了系统的稳定性,因为抽象是不变的;依赖倒置原则的运用还可以减少并行开发引起的风险,提高代码的可读性和维护性。依赖于抽象是面向对象设计的精髓,也是依赖倒置原则的核心。
         依赖倒置原则是许多面向对象技术的优点的根本。合理地应用它对于建立可复用的框架是必要的。对于构建富有变化弹力的代码也是相当重要的。而且,由于抽象和具体相互完全分离,代码的维护就容易很多了。依赖于抽象是一个通用的原则,而某些时候依赖于细节则是在所难免的,必须权衡在抽象和具体之间,方法不是一层不变的,技术只是一种业务关系实现的工具,取舍自知。

7、合成复用原则(Composite Reuse Principle):

合成复用原则又称为组合/聚合原则,其定义如下:

合成复用原则:有限使用独享组合,而不是继承来达到复用的目的。

合成复用原则就是在一个新的对象里通过关联关系(包括组合关系和聚合关系)来使用一些已有的对象,使之成为新对象的一部分;新对象通过委派调用已有对象的方法达到复用功能的目的。简言之:复用时要尽量使用组合/聚合关系(关联关系),少用继承。
      在面向对象设计中,可以通过两种方法在不同的环境中复用已有的设计和实现,即通过组合/聚合关系或通过继承,但首先应该考虑使用组合/聚合,组合/聚合可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少;其次才考虑继承,在使用继承时,需要严格遵循里氏代换原则,有效使用继承会有助于对问题的理解,降低复杂度,而滥用继承反而会增加系统构建和维护的难度以及系统的复杂度,因此需要慎重使用继承复用。
      通过继承来进行复用的主要问题在于继承复用会破坏系统的封装性,因为继承会将基类的实现细节暴露给子类,由于基类的内部细节通常对子类来说是可见的,所以这种复用又称“白箱”复用,如果基类发生改变,那么子类的实现也不得不发生改变;从基类继承而来的实现是静态的,不可能在运行时发生改变,没有足够的灵活性;而且继承只能在有限的环境中使用(如类没有声明为不能被继承)。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值