程序员

Design Pattern

2018-11-19  本文已影响20人  loono

这段时间把 <Design Pattern> 这本书重新复习了一遍,把里面的模式用 Java 实现了一遍。这篇文章会把模式简单描述。

Wikipedia 有很好的资源,每一种模式都有详细的讲解,并且给出了示例。

关于在工作中使用设计模式的一点感想。

1. 模式不能生搬硬套。尽管《设计模式》这本书影响很大,提供了和总结很多思路。毕竟是 20 年前的老书了。在实际应用中,需要灵活的使用。现在大行其道的各种框架中都有原始的这些设计模式的影子。

2. 了解设计模式能够大大节省理解新框架和协同工作的时间。因为各种设计模式的流行,它们已经被使用在大量的现有代码中。了解这些模式,可以更快更好地理解这些代码。

3. 能启发改造和发明新模式的思路。在《设计模式》之后,行业中又发明了大量的新的设计模式,这些模式解决了很多过去和现行的问题。了解这些模式,知晓它们的起源和原理,可以为发明和改造新模式提供思路。


Factory

主要用来创建对象。对于 Client 来讲,传入不同的 Concrete Factory 就可以创建出不同的对象。常见的例子是 UI Style Button. 创建 OSXButton 和 WinButton (实现 Button),分别被 OSXFactory 和 WinFactory (实现 Factory)创建。


Builder

用来创建对象。把具体创建的 Object 的特征和传入创造函数的参数分离,方便表达。同时,加强了不可变性。Builder 本身可以被重用,增强了灵活性。Protobuf 和 AutoValue 等工具会自动生成数据类的对应 Builder。


Prototype 

用于创建对象。好处是节省了创建对象所需要的资源。比如需要提供类默认值的场合,直接使用 Clone 是不错的选择。


Singleton

保证全局只有唯一实例的机制。常用于提供时间,提供网络访问类等等。在多线程情况下,可能要考虑同步锁。与 Dependency Injection 结合使用相得益彰。


Adapter

当需要不兼容的两端兼容时可以使用。在 A 类和 B 类中间加入 AB 类,BA 类,甚至双向调用的类,使两套不同的接口能够相互调用。实际应用中概念泛化了,比如 UI 里常用的 ListViewAdapter 其实是想定义一套接口,并要求 Client 实现。


Bridge

抽象与抽象交互。可能会定义 A B C 三种类,但它们全是抽象类,每种抽象类可以有很多种实现,这样就形成了很多组合。


Composite

为 Client 的调用提供了一套稳定的调用方法,相同的接口。Tree 里的每个 Node 就是一个例子。在具体项目中的例子包括 Flutter 框架里,WIdget 就是用 Composite 构建的。当 Flutter Engine 对 Widget 画图时,只关心它们的 RenderObject 和是否包含 Children。


Decorator

为已知类添加新功能的方法。相比于继承,Decorator 不需要改变原类,只是在原来的类外面包括一层,实现对原来类的功能的扩展。比如对于一个画正方形的类,可以在外包一层类,让其拥有画红色正方形的功能。


Facade

把底层的多个类的具体实现打包成一个接口,方便 Client 调用。比如当我说一句“去买外卖吧”,意味着小王去超市买吃的,小方是菜场买熟食,小李去饭店打包食物。而我得到了丰盛的外卖结果。


Flyweight

乍看起来和 Facade 很像,但是 Flyweight 的重点是可以重用 subsystem 的实例或者结果。因为创建 subsystem 的实例或者得到结果可能很耗时耗资源。所以这些 subsystem 可以在不同的顶层类间重用。


Proxy

为具体实现功能的系统提供了一个关口,外界只能通过这个关口访问功能。主要用于增加权限控制等。Client 调用时,常常不需要知道 Proxy 的存在。


Command

将需要执行的逻辑打包到一个 Command Object 中,由 Client 在适当的时候触发。用一个 UI 领域的例子。比如可以表单可能有两种操作,保存和验证内容,这两种都可以是 Command。当用户填完表单内容以后,表单会把内容传给这两个 Command,并执行它们的功能。Redux Thunk 也算是 Command 的一种。


Chain of responsibility

在 Command 的基础上,当一个 Command 需要被多个部分 Handle 时就需要 Chain of responsibility。比如在 Redux 中,一个 Action 可能会引发一系列的 Middleware,最后被 Reducer 给 handle。


Interpreter

其实就是自定义一套语言规则,这样能够将很复杂的操作用简单的语言来表达。我在工作中,常常把单元测试的不同的实例的创建用字符串来表达,这样测例的表达可以更加简洁。


Mediator

为了避免类之间的相互引用,把调用放到第三方的 Mediator。在 Android 中,EventBus 的概念有点像 Mediator。不过标准的 Mediator 是把类里调用之后 Trigger 的操作内容放到了 Mediator 的实现中。


Observer 

用来管理类之间不同依赖关系的模式,和 Mediator 有点像。大致是多个 Subscriber 通过实现 Listener 接口来监听 subject 的变化。当 subject 改变时,需要调用 listeners 的 update 或者 notify 方法来通知 subscribers。不同的监听方式延伸出了针对事件编程的 reactive programming。


Memento

把当前类的实例的状态保存下来,并且提供根据保存的 Memento 恢复实例的能力。小到 Android 的 Intent,大到 Virtual Machine 做 Snapshot 都是一样的概念。


State

和 Memento 结合来看。Memento 其实就是 State 的简洁表达。假设类实例或者一个状态机,其行为是有当前的状态决定的,State 就是那个状态。


Strategy

Strategy 是将常用的实现打包成类供 Client 调用的方式。比如 Java 中对于 sort 可以定义不同类型的 Comparator 供 sort 使用。


Template

将固定化的流程共享,并且提供给用户(通常是子类)自定义部分实现的模式。从大处来讲,现在大行其道的各种 framework 就是 template,只需要用户填写自己需要控制的 business logic。


Iterator

用来遍历集合内容的模式,已经在不同的语言中大量使用了。每种集合类可以提供一个通用的 Iterator,Client 可以直接使用这个 Iterator 类去访问集合中的内容。这样一套 Client 的实现可以遍历不同类型的集合。


Visitor

为同一种类的类(实现了 accept visitor )提供新功能的方法,和 Iterator 结合起来使用相得益彰。比如,有的 Visitor 可以打印出类的内容,有的 Visitor 可以把类的内容求和等等。只需要写新的 Visitor,不需要改变被访问类,就可以添加新的访问方式。

上一篇下一篇

猜你喜欢

热点阅读