GOF 23种设计模式收集整理

来源:互联网 发布:pcb开料软件 编辑:程序博客网 时间:2024/05/17 04:57


设计模式是软件大师们根据多年来的软件开发经验,对软件开发领域包括合理复用、提高健壮性、减少BUG等各方面作的抽象总结,不同的设计模式方法适合于不同的应用场景,是汇结了他们最宝贵的经验总结。最早的开发模式是1994年GOF四人共同完成的《Design Patterns - Elements of Reusable Object-Oriented Software》一书提及的23种经典设计模式,至今仍是设计模式方面,经典中的经典著作。


创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

一、设计模式的六大原则:
总原则-开闭原则
对扩展开放,对修改封闭。在程序需要进行拓展的时候,不能去修改原有的代码,而是要扩展原有代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。
想要达到这样的效果,我们需要使用接口和抽象类等,后面的具体设计中我们会提到这点。

1、单一职责原则
不要存在多于一个导致类变更的原因,也就是说每个类应该实现单一的职责,否则就应该把类拆分。

2、里氏替换原则(Liskov Substitution Principle)
任何基类可以出现的地方,子类一定可以出现。里氏替换原则是继承复用的基石,只有当衍生类可以替换基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。
里氏代换原则是对“开-闭”原则的补充。实现“开闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。里氏替换原则中,子类对父类的方法尽量不要重写和重载。因为父类代表了定义好的结构,通过这个规范的接口与外界交互,子类不应该随便破坏它。

3、依赖倒转原则(Dependence Inversion Principle)
面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交互,而与具体类的上层接口交互。

4、接口隔离原则(Interface Segregation Principle)
每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接口拆分。使用多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。

5、迪米特法则(最少知道原则)(Demeter Principle)
一个类对自己依赖的类知道的越少越好。无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。
最少知道原则的另一个表达方式是:只与直接的朋友通信。类之间只要有耦合关系,就叫朋友关系。耦合分为依赖、关联、聚合、组合等。我们称出现为成员变量、方法参数、方法返回值中的类为直接朋友。局部变量、临时变量则不是直接的朋友。我们要求陌生的类不要作为局部变量出现在类中。

6、合成复用原则(Composite Reuse Principle)
尽量首先使用合成/聚合的方式,而不是使用继承。


二、UML建模

设计模式最好的记忆方法是熟悉UML建模各种符号表示法(设计模式描述图形表示主要用到类图),通过UML图形记忆可以很清晰的掌握各种设计模式方法的情况,还需要熟练掌握各种方法的应用场景、优缺点等,只有这样才能熟悉应用各种模式方法。

UML类图符号我总结的记忆短句是:聚组泛实依、关联 对应的符号表示是:空实空空实。

具体符号介绍如下:

聚(空)-聚合:
聚合表示整体和部分的关系,这点和组合完成一样,合里的‘部分’可以脱离‘整体’单独使用。

组(实)-组合:
组合表示整体和部分的关系,这点和聚合完成一样,但组合要求涉及的整体和部分是不可分割的部分(通俗点说,A类持有B类,那么B类不可以脱离A类单独实例化),这也是组合和聚合唯一的区别。


泛(空)-泛化:泛化就是继承,是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力,继承是类与类或者接口与接口之间最常见的关系;在Java中此类关系通过关键字extends明确标识,在设计时一般没有争议性。



实(空)-实现:实现就是类实现接口,指的是一个class类实现interface接口(可以是多个)的功能;实现是类与接口之间最常见的关系;在Java中此类关系通过关键字implements明确标识,在设计时一般没有争议性


依(实)-依赖:
也是类与类之间的连接. 表示一个类依赖于另一个类的定义. 依赖关系总是单向 。可以简单的理解,就是一个类A使用到了另一个类B,而这种使用关系是具有偶然性的、、临时性的、非常弱的,但是B类的变化会影响到A;比如某人要过河,需要借用一条船,此时人与船之间的关系就是依赖;表现在代码层面,为类B作为参数被类A在某个method方法中使用。
java 中. 依赖关系体现为: 局部变量, 方法中的参数, 和对静态方法的调用.

关联:

表示类与类之间的联接, 它使一个类知道另一个类的属性和方法. 
关联可以使用单箭头表示单向关联, 使用双箭头或不使用箭头表示双向关联, 不建议使用双向关联. 关联有两个端点, 在每个端点可以有一个基数, 表示这个关联的类可以有几个实例. 
常见的基数及含义: 
0..1:0 或1 个实例. 
0..*: 对实例的数目没有限制. 
1: 只能有一个实例. 
1..*: 至少有一个实例. 

他体现的是两个类、或者类与接口之间语义级别的一种强依赖关系,比如我和我的朋友;这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的,表现在代码层面,为被关联类B以类属性的形式出现在关联类A中,也可能是关联类A引用了一个类型为被关联类B的全局变量;java 语言中关联关系是使用实例变量实现的. 



注:关联、聚合在代码层次很难直接分辨出来,需要理清代码逻辑才能分析清楚类间存在的是关联或聚合关系。

对于继承、实现这两种关系没多少疑问,他们体现的是一种类与类、或者类与接口间的纵向关系;其他的四者关系则体现的是类与类、或者类与接口间的引用、横向关系,是比较难区分的,有很多事物间的关系要想准备定位是很难的,前面也提到,这几种关系都是语义级别的,所以从代码层面并不能完全区分各种关系;但总的来说,后几种关系所表现的强弱程度依次为:组合>聚合>关联>依赖


0 0
原创粉丝点击