0%

Head Frist 设计模式 by Freeman E.

Head First Design Patterns

Head Frist学习原则

  1. 慢一点,你理解的越多,需要记的就越少。
  2. 勤做练习,自己记笔记。
  3. There are no dumb Questions。
  4. 上床睡觉之前不要再看别的书了,或者至少不再看其他有难度的东西。
  5. 要喝水,而且要多喝水。
  6. 大声说出来。
  7. 听听你大脑怎么说。
  8. 要有点感觉!
  9. 设计一些东西!

为什么需要设计模式

  1. 知道OO基础,并不足以让你设计出良好的OO系统。
  2. 良好的OO设计必须具备可复用、可扩展、可维护三个特性。
  3. 模式可以让我们建造出具有良好OO设计质量的系统。
  4. 模式被认为是经过验证的OO设计经验。
  5. 模式不是代码,而是针对设计问题的通用解决方案。你可以把它们应用到特定的应用中。
  6. 模式不是被发明,而是被发现。
  7. 大多数的模式和原则着眼于软件变化的主题。
  8. 大多数的模式都允许系统局部变化独立于其他部分。
  9. 我们常把系统中变化的部分抽出来封装。
  10. 模式让开发人员之间有共享的语言,能够最大化沟通的价值。

OO基础

  1. 抽象(Abstract)
  2. 封装(Encapsulate)
  3. 多态(Polymorphic)
  4. 继承(Inheritance)

OO设计原则

高内聚,低耦合

High cohesion, low coupling.
这是最基本的设计原则,其他原则可以认为是该原则的外延。

单一职责原则(Single Responsibility Priciple)

一个类应该只有一个职责。一个类应该只有一个引起变化的原因。

开闭原则(Open/Closed Priciple)

类应该对扩展开放,对修改关闭。Open to extension and closed to modifcaiton.

遵循开放-关闭原则通常会引入新的抽象层次,增加代码的复杂度。我们要把注意力几种在设计中最有可能改变的地方来应用开闭原则。

里氏代换原则(Liskov Substitution Priciple)

一个可以接受基类对象的地方必然可以接受一个子类对象。

接口隔离原则(Interface Segregation Priciple)

使用多个专门接口来取代一个统一的接口。

依赖倒置原则(Dependence Inversion Principle)

要依赖抽象,不要依赖具体类。

针对接口编程,不针对实现编程(Program to interface, not an implementation)

封装变化(Encapsulate what varies)

合成复用原则(Composite Reuse Principle)

多用组合,少用继承(Composition Favor over inheritance)

为交互对象之间的松耦合设计而努力(loose coupling)

最少知识原则(Least Knowledge Principle)

又称为迪米特法则(Law of Demeter)

只和你的密友谈话。

好莱坞原则(Hollywood Principle)

别调用我们,我们会调用你。(Dont’t call us, we will call you.)

将决策权放在高层模块中,以便决定如何以及何时调用低层模块。

与架构模式、框架、模块的对比

参考一线架构师实践指南
设计模式,相比架构模式应用面更狭窄,针对于特定场景;相比与框架活着模块,更抽象。框架、模块本身也会用到设计模式。

设计模式

策略模式

定义

策略模式(Strategy Pattern)定义算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

  • 设计原则:多用组合,少用继承; 封装变化;针对接口编程,不针对实现编程。

  • IS-A:继承 ; HAS-A/Implements:组合

  • 继承可以在垂直层次上共享代码,但是在水平层次上无能为力;而通过组合可以在水平层面上共享代码。

实现

strategy pattern in ruby

UML

观察者模式

定义

观察者模式(Observer Pattern)在对象之间定义一对多依赖,当一个对象的状态改变时,它的所有依赖者都会收到通知并自动更新。

  • 设计原则 :松耦合;好莱坞原则。

  • 观察者可观察者(主题)之间用松耦合方式结合(loose coupling),可观察者不知道观察者的细节,只知道观察者实现了观察者接口。

  • 使用观察者模式,可以从观察者处推(push)或者拉(pull)数据。

  • 有多个观察者时,不可以依赖特定的通知次序。

实现

observer pattern in ruby

UML

常见场景

GUI框架里的按键等组件,注册不同的观察者到组件的不同类型事件上(如按键按下)。

装饰者模式

定义

装饰者模式(Decorator/Wrapper Pattern)动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

  • 设计原则 :类应对扩展开放,对修改关闭。
  • 装饰者和被装饰者对象有相同的超类,这里利用继承来达到“类型匹配”,而不是用继承来获得“行为”。
  • 可以用一个或多个装饰着包装一个对象。
  • 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为。
  • 装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。
  • 装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂。
  • 装饰者将一个对象包装起来以增加新的行为和责任;适配器将一个对象包装起来以改变其接口;外观将一群对象“包装”起来以简化接口。
  • Decorator IS a component, AND HAS a component.

实现

decorator pattern in ruby

UML

工厂方法模式

定义

工厂方法模式(Factory Method Pattern)定义了创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

  • 设计原则 :要依赖抽象,不要依赖具体类;好莱坞原则。
  • 所有的工厂都是用来封装对象的创建的。
  • 工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象;抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中。
  • 所有的工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合。
  • 工厂方法允许类将实例化延迟到子类。
  • 抽象工厂创建相关的对象家族,而不需要依赖它们的具体类。

实现

factory method pattern in ruby

UML

常见场景

Game里在不同的级别创建地图
插件plugin

抽象工厂模式

定义

抽象工厂模式(Abstract Factory Pattern)提供了一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

与工厂方法模式的主要区别是,抽象共产模式可以创建不同产品类型的组合(只有特定的组合是有意义的)。

实现

UML

常见场景

不同platform(windows,macOS,linux)上的UI
不同的主题(黑底白字,白底黑字)

单件模式

定义

单件模式(Singleton Pattern)确保一个类只有一个实例,并提供一个全局访问点。

  • 在JAVA中实现单件模式需要私有的构造器、一个静态方法和一个静态变量。
  • 确定在性能和资源上的限制,然后小心地选择适当的方案来实现单件,以解决多线程问题(我们必须认定所有的程序都是多线程的)。

实现

singleton pattern in ruby

UML

常见场景

共享资源管理,如线程池(thread pool)、缓存池(cache)、注册表设置(registry setting)。

命令模式

定义

命令模式(Command Pattern)将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

  • 设计原则 :松耦合。
  • 在被解耦的两者之间是通过命令对象进行沟通的,命令对象封装了接受者和一个或一组动作。
  • 调用者通过调用命令对象的execute()发出请求,这会使得接收者的动作被调用。
  • 调用者可以接受命令当作参数,甚至在运行时动态地进行。
  • 命令可以支持撤销,做法是实现一个undo()方法来回到execute()被执行前的状态。
  • 宏命令是命令的一种简单的延伸,允许调用多个命令。宏方法也可以支持撤销。
  • 实际操作时,很常见使用“聪明”命令对象,也就是直接实现了请求,而不是将工作委托给接收者。

实现

UML

常见场景

队列请求(日程安排,线程池,工作队列等),日志请求,事务系统。

适配器模式

定义

适配器模式(Adapter Pattern)将一个类的接口,转换成客户期望的另一个接口。适配器让原来接口不兼容的类可以合作无间。

  • 当使用一个现有的类而其接口并不符合你的需求时,就使用适配器。

  • 适配器改变接口以符合客户的期望。

  • 实现一个适配器可能需要一番功夫,也可能不费功夫,视目标接口的大小与复杂度而定。

  • 适配器有两种形式:对象适配器和类适配器。类适配器需要用到多重继承。

  • 适配器将一个对象包装起来以改变其接口;装饰者将一个对象包装起来以增加新的行为和责任;外观将一群对象“包装”起来以简化接口。

  • 相关模式:外观模式装饰者模式

实现

UML

常见场景

外观模式

定义

外观模式(Facade Pattern)提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

  • 设计原则 :最少知识原则。
  • 当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观。
  • 外观将客户从一个复杂的子系统中解耦。
  • 实现一个外观,需要将子系统组合进外观中,然后将工作委托给子系统执行。
  • 外观将一群对象“包装”起来以简化接口;适配器将一个对象包装起来以改变其接口;装饰者将一个对象包装起来以增加新的行为和责任;
  • 相关模式:适配器模式装饰者模式

实现

UML

常见场景

模板方法模式

定义

模板方法模式(Template Method Pattern)在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

  • 设计原则 :好莱坞原则。
  • 模板方法是一种重要的代码复用技巧。
  • 模板方法的抽象类可以定义具体方法、抽象方法和钩子。
  • 钩子是一种方法,它在抽象类中不做事,活着只做默认的事情,子类可以选择要不要取覆盖它。
  • 策略模式和模板方法模式都封装算法,一个用组合,一个用继承。
  • 工厂方法由子类决定实例化哪个类,是模板方法的一个特殊版本。
  • 相关模式:工厂方法策略模式

实现

UML

常见场景

排序算法(CompareTo接口),Swing窗口,Applet

外观模式

定义

外观模式(Facade Pattern)提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

  • 设计原则 :最少知识原则。
  • 当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观。
  • 外观将客户从一个复杂的子系统中解耦。
  • 实现一个外观,需要将子系统组合进外观中,然后将工作委托给子系统执行。
  • 外观将一群对象“包装”起来以简化接口;适配器将一个对象包装起来以改变其接口;装饰者将一个对象包装起来以增加新的行为和责任;
  • 相关模式:适配器模式装饰者模式

实现

UML

常见场景

迭代器模式

定义

迭代器模式(Iterator Pattern)提供一种方法顺序访问一个聚合(aggregate)对象的各个元素,而又不暴露其内部的表示。

  • 设计原则 :封装变化;单一职责。
  • 迭代器将遍历聚合的工具封装进一个对象中。
  • 当使用迭代器的时候,我们依赖聚合提供遍历。
  • 把游走的任务放在迭代器上,而不是聚合上。这样简化了聚合的接口和实现,也让责任各得其所。
  • 迭代器提供了一个通用的接口,让我们遍历聚合的项,当我们编码使用聚合的项时,就可以使用多态机制。
  • 对迭代器而言,数据结构可以是有次序的,或者没有次序的,甚至数据可以重复的。除非某个集合的文件有特别说明,否则不可以对迭代器取出元素的大小顺序作假设。

实现

UML

常见场景

排序算法(CompareTo接口),Swing窗口,Applet
Reference:

  1. strategy pattern in ruby
  2. 单例模式的八种写法比较
  3. Evaluating Alternative Decorator Implementations In Ruby
  4. bullMind
  5. Design Patterns in Object Oriented Programming