一, 引子
库与框架无法帮助我们将应用组织成容易了解, 容易维护, 具有弹性的架构, 所以需要设计模式!
使用模式最好的方式是:"把模式装进脑子里, 然后在你的设计和已有的应用中, 寻找何处可以使用它们".
以往是代码复用, 现在是经验复用!
模式是在某情境 (Context) 下, 针对某问题的某种解决方案.
情境就是应用某个模式的情况, 这应该是会不断出现的情况;
问题就是你想在某情境下达到的目标, 但也可以是某情境下的约束;
解决方案就是你所追求的: 一个通用的设计, 用来解决约束, 达到目标.
模式就是如果你发现自己处于某个情境下, 面对着所欲达到的目标被一群约束影响着的问题, 然后, 你能够应用某个设计, 克服这些约束并达到该目标, 将你领向某个解决方案.
OOP(面向对象编程)的四大特性: 抽象, 封装, 多态, 继承.
抽象: 抽象是提取现实世界中某事物的关键特性, 为该事物构建模型的过程. 对同一事物中不同的需求下, 需要提取的特性可能不一样. 得到的抽象模型中一般包含: 属性 (数据) 和操作(行为). 这个抽象模型我们称之为类, 通过对类进行实例化得到具体的对象.
封装: 封装可以使类具有独立性和隔离性, 从而保证类的高内聚. 只暴露给类外部或者子类必须的属性和操作. 类封装的实现依赖类的修饰符(public,protected 和 private).
继承: 继承是对现有类的一种复用机制. 一个类如果继承现有的类, 则这个类将拥有被继承类的所有非私有特性(属性和操作). 这里指的继承包含类的继承和接口的实现. 常见的继承方法有共有继承, 私有继承, 多重继承, 多层继承.
多态: 多态是中继承的基础上实现的. 多态的三个要素: 继承, 重写和父类引用指向子类的对象. 父类引用指向不同的子类对象时, 调用相同的方法, 呈现出不同的行为; 就是类的多态性. 多态还可分为编译时多态 (静态多态性) 和运行时多态(动态多态性). 另外类的函数重载, 运算符重载, 也可算为多态的特性.
二, 策略模式
[设计原则 1] : 找出应用中可能需要变化之处, 把它们独立出来, 不要和那些不需要变化的代码混在一起.
把会变化的部分取出并封装起来, 以便以后可以轻易地改动或扩展此部分, 而不影响不需要变化的其他部分.
[设计原则 2] : 针对接口编程, 而不是针对实现编程.
针对接口编程真正的意思是: 针对超类型 (supertype) 编程.
针对实现编程:
- Dog d = new Dog();
- d.bark()
针对接口编程:
- Animal animal = new Dog();
- animal.bark();
这样可以在运行时才指定具体实现的对象.
[设计原则 3] : 多用组合, 少用继承.
利用继承设计子类的行为, 是在编译时静态决定的, 而且所有的子类都会继承到相同的行为; 而利用组合的做法扩展对象的行为, 就可以在运行时动态地进行扩展.
使用组合建立系统具有很大的弹性, 不仅可将算法族封装成类, 更可以 "在运行时动态地改变行为", 只要组合的行为对象符合正确的接口标准即可.
类之间的关系可以描述为: IS-A(是一个, 组合过来的 -|>),HAS-A(有一个, 继承过来的 ->)和 IMPLEMENTS(实现, 接口的实现....|>).
[设计模式 1: 策略模式] : 定义了算法族, 分别封装起来, 让她们之间可以互相替换, 此模式让算法的变化独立于使用算法的客户.
image
策略模式的核心是将算法单独进行封装成类, 将变化独立于客户, 然后使用组合模式的方法与客户组合, 从而形成可扩展, 可运行时替换的一种模式.
核心要点:
知道 OO 基础, 并不足以让你设计出良好的 OO 系统;
良好的 OO 设计必须具备可复用, 可扩充, 可维护三个特性;
模式可以让我们建造出具有良好 OO 设计质量的系统;
模式被认为是历经验证的 OO 设计经验;
模式不是代码, 而是针对设计问题的通用解决方案. 你可以把它应用到特定的应用中去.
模式不是被发明, 而是被发现;
大多数的模式和原则, 都着眼于软件变化的主题;
大多数的模式都允许系统局部改变独立于其他部分;
我们常把系统中会变化的部分抽出来封装;
默认让开发人员之间有共享语言, 能够最大化沟通的价值.
三, 观察者模式
[设计模式 2: 观察者模式] : 定义了对象之间的一对多依赖, 这样一来, 当一个对象改变状态时, 它的所有依赖者都会收到通知并自动更新.
image
[设计原则 4] : 为了交互对象之间的松耦合设计而努力.
松耦合的设计之所以能让我们建立有弹性的 OO 系统, 能够应付变化, 是因为对象之间的互相依赖降到了最低.
核心要点:
观察者模式定义了对象之间一对多的关系;
主题 (也就是可观察者) 用一个共同的接口来更新观察者;
观察者和可观察者之间用松耦合方式结合(loosecoupling), 可观察者不知道观察者的细节, 只知道观察者实现了观察者的接口.
使用观察者模式, 你可以从被观察者处推或者拉数据, 只是对于这个模式而言, 推的方式更 "正确".
有多个观察者时, 不可以依赖特定的通知次序;
四, 装饰者模式
[设计原则 5] : 类应该对扩展开放, 对修改关闭.
我们的目标是允许类容易扩展, 在不修改现有代码的情况下, 就可搭配新的行为. 这样的设计具有弹性可以应对改变, 可以接受新的功能来应对改变的需求.
[设计模式 3: 装饰者模式] : 动态地将责任附加到对象上. 若要扩展功能, 装饰者提供了比继承更有弹性的替代方案.
image
image
装饰者和被装饰者必须是一样的类型: 我们利用继承达到 "类型匹配", 而不是利用继承获得 "行为".
核心要点:
继承属于扩展形式之一, 但不见得是达到弹性设计的最佳方案;
在我们的设计中, 应该允许行为可以被扩展, 而无须修改现有代码;
组合和委托可用于在运行时动态地加上新的行为;
除了继承, 装饰者模式也可以让我们扩展行为;
装饰者模式意味着一群装饰者类, 这些类用来包装具体组件;
装饰者类反映出被装饰的组件类型(事实上, 他们具有相同的类型, 都经过接口或继承实现);
装饰者可以在被装饰者的行为前面与 / 或后面加上自己的行为, 甚至将被装饰者的行为整个取代, 而达到特定的目的.
你可以用无数个装饰者包装一个组件;
装饰者一般对组件的客户是透明的, 除非客户程序依赖于组件的具体类型;
装饰者会导致设计中出现许多小对象, 如果过度使用, 会让程序变得很复杂.
五, 工厂模式
当我们直接实例化一个对象时, 就是在依赖它的具体类.
所有工厂 (Factory) 模式都是用来封装对象的创建. 工厂模式核心就是将对象创建过程的代码抽离出来放在一起便于后续修改和维护, 而将创建对象之后的使用流程固化保持不变.
[设计模式: 静态工厂] : 由静态方法 (函数) 来处理对象的创建.
[设计模式: 简单工厂] : 由工厂类 (SimplePizzaFactory) 来处理对象的创建, 客户类 (PizzaStore) 负责产品 (Pizza) 的制作.
image
[设计模式: 工厂模式] : 由工厂超类 (PizzaStore) 来处理对象的使用, 工厂子类 (NYPizzaStore,ChicagoPizzaStore) 处理对象 (Pizza) 的创建. 工厂超类的创建方法是抽象的, 所以以来子类来处理对象的创建; 工厂子类创建的对象作为工厂方法返回的产品, 而这产品通常会在工厂超类的其他方法中使用. 从而将对象的使用流程 (通常是固定的) 与对象 / 产品的实际创建过程 (通常是变化的) 分隔开来.
image
[设计模式 4: 工厂方法模式] : 定义了一个创建对象的接口, 但由子类决定要实例化的类是哪一个. 工厂方法让类把实例化推迟到子类.
这里说的子类 "决定", 并不是指模式允许子类本身在运行时做决定, 而是指在编写创建者类时, 不需要知道实际创建的产品是哪一个. 选择了使用哪个子类, 自然就决定了实际创建的产品是什么.
[设计模式 5: 抽象工厂模式] : 提供一个接口, 用于创建相关或依赖对象的家族, 而不需要明确指定具体类.
image
Pizza 原料抽象工厂实例:
image
通过抽象工厂提供的接口, 可以创建产品的家族, 利用这个接口书写代码, 我们的代码将从实际工厂解耦, 以便在不同上下文中实现各式各样的工厂, 制造出各种不同的产品. 因为代码从实际的产品中解耦了, 所以我们可以替换不同的工厂来取得不同的行为.
image
简单工厂与工厂模式的区别: 工厂模式中具体商店是扩展自一个类, 这个类有一个抽象方法 createPizza(), 而由每个商店自行负责 createPizza()方法的行为; 而在简单工厂中, 只是把对象的创建封装起来, 它只是由 Pizzastore 使用的对象而已, 它不能变更正在创建的产品, 因此不具备工厂方法的弹性.
工厂模式与抽象工厂的区别: 工厂模式使用的是类而抽象工厂使用的是对象; 工厂模式使用的是集成, 而抽象工厂是通过对象的组合; 他们都负责将客户从具体类型 / 产品中解耦, 但抽象工厂可以把一群相关产品集合起来; 抽象工厂可用来创建整个产品家族, 而工厂模式只能用来创建产品; 也可理解为抽象工厂可创建一群相关产品创建的工厂方法, 再由具体的工厂方法创建产品, 而工厂模式只是其中一个工厂方法, 只能创建一类产品而已.
image
image
[设计原则 6] : 要依赖抽象, 不要依赖具体类!(也称为依赖倒置原则: Dependency Inversion Principle).
如下指导方针能帮助使用依赖倒置原则:
变量不可以持有具体类的引用: 如果使用 new, 就会持有具体类的引用; 可以使用工厂方法来避开这样的做法;
不要让类派生自具体类: 如果派生自具体类, 你就会依赖具体类. 请派生自一个抽象(接口或抽象类);
不要覆盖基类中已实现的方法: 如果覆盖基类已实现的方法, 那么你的基类就不是一个真正适合被继承的抽象. 基类中已实现的方法, 应该由所有的子类共享.
核心要点:
所有的工厂都是用来封装对象的创建的;
简单工厂, 虽然不是真正的设计模式, 但仍不失为一个简单的方法, 可以将客户程序从具体类解耦;
工厂方法使用继承: 把对象的创建委托给子类, 子类实现工厂方法来创建对象;
抽象工厂使用对象组合: 对象的创建被实现在工厂接口所暴露出来的方法中;
所有的工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合;
工厂方法允许类将实例化延迟到子类进行;
抽象工厂创建相关的对象家族, 而不需要依赖它们的具体类;
依赖倒置原则, 指导我们避免依赖具体类型, 而要尽量依赖抽象;
工厂是很有威力的技巧, 帮助我们针对抽象编程, 而不要针对具体类编程.
六, 单件模式
[设计模式 6: 单件模式] : 确保一个类只有一个实例, 并提供一个全局访问点.
image
核心要点:
单件模式确保程序中一个类最多只有一个实例;
单件模式也提供访问这个实例的全局点;
在 JAVA 中实现单件模式需要私有构造器, 一个静态方法和一个静态变量;
确定在性能和资源上的限制, 然后小心地选择适当的方案来实现单件, 以解决多线程的问题;
如果使用多个类加载器, 可能导致单件模式失效而产生多个实例;
七, 命令模式
[设计模式 7: 命令模式] : 将 "请求" 封装成对象, 以便使用不同的请求, 队列或者日志来参数化其他对象. 命令模式也支持可撤销的操作.
image
核心要点:
命令模式将发出请求的对象和执行请求的对象解耦;
在被解耦的两者之间是通过命令对象进行沟通的; 命令对象封装了接收者和一个或一组动作;
调用者通过调用命令对象的 execute()发出请求, 这会使得接收者的动作被调用;
调用者可以接受命令当做参数, 甚至在运行时动态地进行(便于扩展);
命令可以支持撤销, 做法是实现一个 undo()方法来回到 execute()被执行前的状态;
宏命令是命令的一种简单的延伸, 允许调用多个命令; 宏方法也可以支持撤销;
实际操作时, 很常见使用 "聪明" 命令对象, 也就是直接实现了请求, 而不是将工作委托给接收者;
命令也可以用来实现队列, 日志和事物处理.
八, 适配器模式(Adapter-Pattern)
[设计模式 8: 适配器模式] : 将一个类的接口, 转换成客户期望的另一个接口. 适配器让原本接口不兼容的类可以合作无间.
image
上面的类图是 "对象" 适配器, 还有一种是 "类" 适配器. 它们唯一的区别在于类适配器继承了(多重继承)Target 和 Adaptee; 而对象适配器利用组合的方式将请求传送给被适配者.
image
装饰者模式与适配器模式: 装饰者模式的工作是扩展包装对象的行为或责任, 不会改变被包装对象的接口; 而适配器模式是会改变被适配对象的接口的.
九, 外观模式(Facade-Pattern)
[设计模式 9: 外观模式] : 提供了一个统一的接口, 用来访问子系统中的一群接口. 外观定义了一个高层接口, 让子系统更容易使用.
image
适配器模式与外观模式: 适配器模式和外观模式都可以将一个或多个类接口转换为统一的, 简化的接口. 但两种模式之间的差异, 不在于它们 "包装" 了几个类, 而在于它们不同的意图: 适配器模式的意图是 "改变" 接口以符合客户的期望; 外观模式的意图是提供子系统的一个简化接口.
[设计原则 7] : 最少知识原则: 只和你的密友谈话.
最少知识 (Least Knowledge) 原则告诉我们要减少对象之间的交互, 只留下几个 "密友".
外观 / 装饰 / 适配器:
外观: 让接口更简单;
装饰: 装饰对象以增加新的责任 / 行为;
适配器: 将一个接口转成另一个接口.
核心要点:
当需要使用一个现有的类而其接口并不符合你的需要时, 就使用适配器;
当需要简化统一一个很大的接口或者一群复杂的接口时, 使用外观;
适配器改变接口以符合客户的期望;
外观将客户从一个复杂的子系统中解耦;
实现一个适配器可能需要一番功夫, 也可能不费功夫, 视目标接口的大小与复杂度而定;
实现一个外观, 需要将子系统组合进外观中, 然后将工作委托给子系统进行;
适配器模式有两种形式: 对象适配器和类适配器; 对象适配器使用组合, 类适配器则用到多重继承;
你可以将一个子系统实现一个以上的外观;
适配器将一个对象包装起来以改变接口; 装饰者将一个对象包装起来以增加新的行为和责任; 而外观将一群对象 "包装" 起来以简化其接口.
十, 模板方法模式
[设计模式 10: 模版方法模式] : 在一个方法中定义一个算法的骨架, 而将一些步骤延迟到子类中. 模板方法使得子类可以在不改变算法结构的情况下, 重新定义算法中的某些步骤.
image
image
模版方法与策略模式: 策略模式定义了一个算法族, 并采用对象组合的方法, 让这些算法可以动态互换; 而模版方法是定义了一个算法大纲 / 框架, 并采用继承的方法, 由子类定义其中算法中某些步骤的内容. 策略模式更有弹性, 而模板方法对算法拥有更多的控制权, 且可防止重复代码.
[设计原则 8] : 好莱坞原则: 别调用 (打电话给) 我们, 我们会调用 (打电话给) 你.
好莱坞原则, 可以让我们防止依赖腐败: 当高层组件依赖低层组件, 而底层组件又依赖高层组件, 而高层组件又依赖边侧组件, 而边侧组件又依赖低层组件时, 依赖腐败就发生了. 在这种情况下, 没有人可以轻易地搞懂系统是如何设计的.
image
在好莱坞原则之下, 我们允许低层组件将自己挂钩到系统上, 但是高层组件会决定什么时候和怎样使用这些低层组件. 换句话说: 高层组件对待低层组件的方式是 "别调用我们, 我们会调用你".
策略 / 模板 / 工厂:
策略: 封装可互换的行为, 然后使用委托来决定要采用哪一个行为;
模板: 子类决定如何实现算法中的某些步骤;
工厂: 由子类决定实例化哪个具体类
核心要点:
"模板方法" 定义了算法的步骤, 把这些步骤的实现延迟到子类;
模板方法模式为我们提供了一种代码复用的重要技巧;
模版方法的抽象类可以定义具体方法, 抽象方法和钩子; 抽象方法由子类实现; 钩子是一种方法, 它在抽象类中不做事, 或者只做默认的事, 子类可以选择要不要去覆盖它;
为了防止子类改变模板方法中的算法, 可以将模版方法声明为 final;
好莱坞原则告诉我们, 将决策权放在高层模块中, 以便决定如何以及何时调用底层模块;
策略模式和模板方法模式都封装算法, 单策略用组合, 模板用继承;
工厂方法是模板方法的一种特殊版本(工厂方法封装创建对象的算法).
十一, 迭代器模式(Interator-Pattern)
[设计模式 11: 迭代器模式] : 提供一种方法顺序访问一个聚合对象中的各个元素, 而又不暴露其内部的表示.
image
image
迭代器模式让我们能游走于聚合内的每一个元素, 而又不暴露其内部的表示. 迭代器模式把游走的任务放在迭代器上, 而不是聚合上, 这样简化了聚合的接口和实现, 也让责任各得其所.
[设计原则 9] : 单一责任原则: 一个类应该只有一个引起变化的原因.
类的每个责任都有改变的潜在区域, 超过一个责任, 就意味着超过一个改变的区域. 这个原则告诉我们, 尽量让每个类保持单一责任! 然而设计的困难点就在于: 如何区分设计中的不同责任!
内聚用来衡量一个类或模块紧密地达到单一目的或责任. 当一个模块或一个类被设计成只支持一组相关的功能时, 我们说它有高内聚; 反之, 当被设计成支持一组不想关的功能时, 我们说它具有低内聚.
迭代器与集合: Collection 和 Interator 的好处在于, 每个 Collection 都知道如何创建自己的 Interator. 只要调用 Collection 中的 interator(), 就可以返回一个具体的 Interator, 而你根本不需要知道或关心到底是用了哪个具体类, 你只要使用它的 Interator 接口就可以了.
十二, 组合模式(Component Pattern)
[设计模式 12: 组合模式] : 允许你将对象组合成树形结构来表现 "整体 / 部分" 层次结构. 组合能让客户以一致的方式处理个别对象以及对象组合.
image
image
组合模式让我们能用树形方式创建对象的结构, 树里面包含了组合以及个别的对象. 使用组合结构, 我们能把相同的操作应用在组合和个别对象上; 换句话说, 在大多数情况下, 我们可以忽略对象组合和个别对象之间的差异.
策略 / 外观 / 组合 / 适配器 / 迭代器 / 观察者:
策略: 封装可互换的行为, 并使用委托决定使用哪一个;
组合: 客户可以将对象的集合以及个别的对象一视同仁;
外观: 简化一群类的接口;
适配器: 改变一个或多个类的接口;
迭代器: 提供一个方式来遍历集合, 而无须暴露集合的实现;
观察者: 当某个状态改变时, 允许一群对象能被通知到.
核心要点:
迭代器允许访问聚合的元素, 而不需要暴露它的内部结构;
迭代器将遍历聚合的工作封装进一个对象中;
当使用迭代器的时候, 我们依赖聚合提供遍历;
迭代器提供了一个通用的接口, 让我们遍历聚合的项, 当我们编码使用聚合的项时, 就可以使用多态机制;
我们应该努力让一个类只分配一个职责;
组合模式提供一个结构, 可同时包容个别对象和组合对象;
组合模式允许客户对个别对象以及组合对象一视同仁;
组合结构内的任意对象称为组件, 组件可以是组合, 也可以是叶节点;
在实现组合模式时, 有许多设计上的折衷. 你要根据需要平衡透明性和安全性.
十三, 状态模式
[设计模式 13: 状态模式] : 允许对象在内部状态改变时改变它的行为, 对象看起来好像修改了它的类.
image
策略模式与状态模式: 策略模式与状态模式的类图很类似, 它们的差异在于他们的意图: 策略模式是继承之外的一种弹性替代方案, 状态模式则是许多条件判断的替代方案.
状态 / 策略 / 模板方法:
状态: 封装基于状态的行为, 并将行为委托到当前状态;
策略: 将可以互换的行为封装起来, 然后使用委托的方法, 决定使用哪一个行为;
模板方法: 由子类决定如何实现算法中的某些步骤, 模板提供算法的完整步骤.
核心要点:
状态模式允许一个对象基于内部状态而拥有不同的行为;
和程序状态机 (PSM) 不同, 状态模式用类代表状态;
Context 会将行为委托给当前的状态对象;
通过将每个状态封装进一个类, 我们把以后需要做的任何改变局部化了;
状态模式和策略模式有相同的类图, 但是它们的意图不同: 策略模式通常会用行为或算法来配置 Context 类; 状态模式允许 Context 随着状态的改变而改变行为;
状态转换可以由 State 类 (内部) 或 Context 类 (外部) 控制;
使用状态模式通常会导致设计中类的数据大量增加;
状态类可以被多个 Context 实例共享.
十四, 代理模式(Proxy-Pattern): 控制对象访问
[设计模式 14: 代理模式] : 为另一个对象提供一个替身或占位符以控制对这个对象的访问.
image
代理模式分为: 本地代理, 远程代理(控制访问远程对象), 虚拟代理(控制访问创建开销大的资源), 保护代理(基于权限控制对资源的访问), 缓存代理(维护之前创建的对象返回缓存对象). 下图是 JAVA 的 java.lang.reflect 包中的动态代理:
image
代理模式与适配器模式: 代理模式和适配器模式都是挡在其他对象的前面, 并负责请求转发给它们. 适配器会改变对象的接口, 而代理模式则实现相同的接口.
代理模式与装饰者模式: 它们看起来的确很像, 但是两者的目的不一样: 装饰者是为对象增加行为, 而代理则是控制对象的访问; 装饰者装饰对象, 而代理是代表对象. 而且装饰者是不会实例化对象的, 而代理模式可能会实例化对象的.
装饰者 / 适配器 / 外观 / 代理:
装饰者: 包装另一个对象, 并提供额外的行为;
适配器: 包装另一个对象, 并提供不同的接口;
外观: 包装另一个 / 许多对象, 以简化它们的接口;
代理: 包装另一个对象, 并控制对它的访问.
核心要点:
代理模式为另一个对象提供代表, 以便控制客户对对象的访问, 管理访问的方式有许多种;
远程代理管理客户和远程对象之间的交互;
虚拟代理控制访问实例化开销大的对象;
保护代理基于调用者控制对象对象方法的访问;
代理模式还有许多变体, 如: 缓存代理, 同步代理, 防火墙代理和写入时复制代理等;
代理在结构上类似装饰者, 但两者目的不同: 装饰者模式为对象加上行为, 而代理则是控制访问;
就和其他的包装者 (wrapper) 一样, 代理会造成你的设计中类的数据增加.
十五, 复合模式
在解决具体问题的时候, 必须要考虑采用模式是否有意义, 绝对不能为了使用模式而使用模式.
模式通常被一起使用, 并被组合在同一个设计解决方案中. 复合模式就是在一个解决方案中结合两个或多个模式, 以解决一般或重复发生的问题.
MVC 复合模式: 模型利用 "观察者" 让控制器和视图可以随最新的状态改变而更新; 视图和控制器则实现了 "策略模式", 控制器是视图的行为, 如果你希望有不同的行为, 可以直接换一个控制器; 视图内部又使用 "组合模式" 来管理窗口, 按钮以及其他显示组件.
image
image
image
控制器把控制逻辑从视图中分离, 让模型和视图之间解耦.
Modle 2 复合模式: 是 MVC 在 web 上的应用.
image
image
核心要点:
MVC 是复合模式, 结合了观察者模式, 策略模式和组合模式;
模型使用观察者模式, 以便观察者更新, 同时保持两者之间解耦;
控制器是视图的策略, 视图可以使用不同的控制器实现, 得到不同的行为;
视图使用组合模式实现用户界面, 用户界面通常组合了嵌套的组件, 像面板, 框架和按钮;
这些模式携手合作, 把 MVC 模型的三层解耦, 这样可以保持设计干净又有弹性;
适配器模式用来将新的模型适配成已有的视图和控制器;
Model 2 是 MVC 在 Web 上的应用;
在 Model 2 中, 控制器实现成 Servlet, 而 JSP/html 实现视图.
十六, 与设计模式相处
模式是在某情境 (Context) 下, 针对某问题的某种解决方案.
情境就是应用某个模式的情况, 这应该是会不断出现的情况;
问题就是你想在某情境下达到的目标, 但也可以是某情境下的约束;
解决方案就是你所追求的: 一个通用的设计, 用来解决约束, 达到目标.
模式就是如果你发现自己处于某个情境下, 面对着所欲达到的目标被一群约束影响着的问题, 然后, 你能够应用某个设计, 克服这些约束并达到该目标, 将你领向某个解决方案.
千万记住: 模式是被 "发现的", 而不是被 "创建的".
一句话描述各设计模式:
命令: 封装请求称为对象;
外观: 简化一群类的接口;
单件: 确保有且只有一个对象被创建;
代理: 包装对象, 以控制对此对象的访问;
组合: 客户用一致的方式处理对象集合和单个对象;
状态: 封装了基于状态的行为, 并使用委托在行为之间切换;
策略: 封装可以互换的行为, 并使用委托来决定要使用哪一个;
适配器: 封装对象, 并提供不同的接口;
观察者: 让对象能够在状态改变时被通知;
装饰者: 包装一个对象, 以提供新的行为;
迭代器: 在对象的集合之中游走, 而不暴露集合的实现;
模板方法: 由子类决定如何实现一个算法中的步骤;
工厂方法: 由子类决定要创建的具体类是哪一个;
抽象工厂: 允许客户创建对象的家族, 而无需指定他们的具体类;
模式的分类: 创建型, 行为型和结构型:
image
注意: 怎么分类不重要, 重要的是了解这些模式和它们之间的关系.
用模式思考(能够看清设计, 体会着什么地方模式能自然适用, 在什么地方模式则不能):
将你的思维集中在设计本身, 而不是在模式上;
我们的目标是简单, 而不是如何应用模式;
加入模式是要应对未来可能发生的改变;
重构是要改善其结构, 而不改变其行为; 在改变结构时可以考虑应用模式;
核心要点:
让设计模式自然而然地出现在你的设计中, 而不是为了使用而使用;
设计模式并非僵化的教条; 你可以依据自己的需要采用或调整;
总是使用满足需要的最简单解决方案, 不管它用不用模式;
学习设计模式的类目, 可以帮你自己熟悉这些模式以及它们之间的关系;
模式的分类 (或分类) 是将模式分成不同的族群, 如果这么做对你有帮助, 就采用吧!
你必须相当专注才能狗称为一个模式的作家: 这需要时间也需要耐性, 同时还必须乐意做大量的精化工作;
模式能够为你带来的最大好处之一是: 让你的团队拥有共享词汇.
来源: http://www.jianshu.com/p/3c6f0c8b15ff