关于
我的项目
相关阅读
热度排行
- [转] 宫崎骏用动漫教给我们的人生哲理,每一句都能说到心里! - (日期:[八月 24, 2013] 点击:[53,424])
- Google 网页爬虫报告无法连接站点解决办法 - (日期:[七月 20, 2014] 点击:[38,652])
- 架设Tiny Tiny RSS(TTRSS)阅读器,找回Google Reader! - (日期:[九月 27, 2013] 点击:[27,785])
- SkyDrive、DropBox和Google Drive三大公有云存储服务对比 - (日期:[六月 25, 2013] 点击:[25,607])
- 升级到至强E5440后,与i5 CPU笔记本性能对比 - (日期:[二月 18, 2014] 点击:[23,754])
- 公钥私钥加密解密数字证书数字签名详解 - (日期:[四月 19, 2014] 点击:[22,968])
- 本站建站技术合集 - (日期:[九月 20, 2013] 点击:[22,522])
- 使用OpenerDNS解决无法访问Google的问题 - (日期:[七月 5, 2014] 点击:[21,822])
- WordPress博客添加“返回顶部”按钮 - (日期:[七月 14, 2013] 点击:[21,225])
- Linux文件系统基础之inode和dentry - (日期:[三月 13, 2015] 点击:[20,181])
- 云存储中的HTTP鉴权算法分析 - (日期:[二月 7, 2014] 点击:[18,647])
- 存储基础知识之——磁盘阵列原理及操作实战 - (日期:[二月 9, 2014] 点击:[17,513])
- 精选37条强大的常用linux shell命令组合 - (日期:[九月 4, 2013] 点击:[17,442])
- DNS原理、架构和配置详解 - (日期:[九月 6, 2013] 点击:[16,820])
- Netty和Jetty的Java NIO 网络框架模型分析 - (日期:[七月 13, 2013] 点击:[16,339])
- CoreOS 初识之安装 - (日期:[十一月 16, 2014] 点击:[16,191])
- Windows与Linux文件系统互访的几种方法 - (日期:[八月 21, 2014] 点击:[15,737])
- Dijkstra算法求解最短路径分析 - (日期:[七月 12, 2014] 点击:[14,933])
- NAS解决方案实现多媒体文件共享播放 - (日期:[十二月 21, 2014] 点击:[13,941])
- 简介 - (日期:[九月 1, 2012] 点击:[13,771])
- 如何编程实现 2 + 2 = 5? - (日期:[六月 2, 2014] 点击:[13,273])
- 搭建了一个iNews程序 - (日期:[十月 15, 2013] 点击:[13,246])
- 2014年9月曝出的Bash ShellShock漏洞简析 - (日期:[九月 26, 2014] 点击:[13,147])
- 彻底解决WordPress博客垃圾评论的问题 - (日期:[八月 5, 2013] 点击:[13,107])
- 如何使用1M的内存排序100万个8位数 - (日期:[三月 27, 2014] 点击:[12,561])
- 全部日志列表 - (日期:[十一月 11, 2012] 点击:[12,364])
- 关于回调函数和this指针探讨 - (日期:[八月 24, 2014] 点击:[12,225])
- 给定一个long型常量,其值为x,给定long型变量a,要求a & x 的取值集合 - (日期:[九月 8, 2012] 点击:[11,713])
- 开源好用的电子书管理服务Talebook(Calibre网络版)安装使用指南 - (日期:[四月 23, 2022] 点击:[11,506])
- WordPress建站必备实用插件 - (日期:[八月 7, 2014] 点击:[11,369])
分类目录
文章归档
- 2025年一月 (1)
- 2024年十二月 (1)
- 2024年四月 (1)
- 2024年二月 (1)
- 2023年九月 (1)
- 2023年一月 (1)
- 2022年十月 (1)
- 2022年八月 (2)
- 2022年四月 (1)
- 2022年三月 (1)
- 2021年十二月 (2)
- 2021年十月 (2)
- 2021年九月 (1)
- 2021年八月 (1)
- 2021年五月 (1)
- 2021年三月 (2)
- 2021年一月 (2)
- 2020年十二月 (5)
- 2020年十一月 (2)
- 2020年十月 (2)
- 2020年九月 (1)
- 2020年八月 (5)
- 2020年七月 (2)
- 2019年九月 (1)
- 2018年八月 (1)
- 2018年七月 (1)
- 2018年六月 (1)
- 2018年五月 (1)
- 2018年三月 (1)
- 2018年二月 (1)
- 2018年一月 (2)
- 2017年十二月 (3)
- 2017年十月 (4)
- 2017年九月 (1)
- 2017年七月 (1)
- 2017年六月 (1)
- 2016年十二月 (1)
- 2016年十月 (1)
- 2016年九月 (1)
- 2016年七月 (2)
- 2016年六月 (1)
- 2016年二月 (3)
- 2015年十二月 (3)
- 2015年十一月 (2)
- 2015年十月 (1)
- 2015年八月 (2)
- 2015年七月 (4)
- 2015年六月 (1)
- 2015年三月 (2)
- 2015年二月 (1)
- 2015年一月 (4)
- 2014年十二月 (2)
- 2014年十一月 (2)
- 2014年十月 (5)
- 2014年九月 (8)
- 2014年八月 (11)
- 2014年七月 (17)
- 2014年六月 (7)
- 2014年五月 (15)
- 2014年四月 (16)
- 2014年三月 (14)
- 2014年二月 (5)
- 2013年十二月 (5)
- 2013年十一月 (3)
- 2013年十月 (13)
- 2013年九月 (13)
- 2013年八月 (13)
- 2013年七月 (9)
- 2013年六月 (8)
- 2013年五月 (1)
- 2013年三月 (3)
- 2013年一月 (1)
- 2012年十一月 (1)
- 2012年九月 (12)
- 2012年八月 (3)
- 2011年二月 (1)
- 2009年三月 (1)
- 2009年二月 (1)
- 2008年十一月 (1)
- 2008年六月 (1)
- 2008年四月 (1)
- 2008年三月 (1)
[转] 一句话总结GoF 23种设计模式
以GoF的经典教材为例,一句话总结个人的理解。
OO回顾
- 四大概念
- 抽象:抽象为了简化问题,简单即美,相信我,人类很笨
- 继承:为了便于扩展或改写原有的功能
- 多态:为了便于改写原有的功能
- 封装:组件化,便于理解、替换与复用,因此系统会更加灵活(后文提到封装XXX时,就不具体说这些优点了)
- 类关系
- 依赖:非常弱的关系,A中用过B即为A依赖B
- 继承:子类
- 实现:接口/抽象类
- 关联(也常看做包含)
- 聚合:has-a,部分与整体的生命周期可以不同
- 组合:contains-a,更强,部分依赖整体的生命周期
- 接口
这里单独强调下接口,作为最重要的抽象形式之一,接口可以看做设计模式的基石,所以面向接口编程被广泛采用。接口即契约。好的接口必须小而精(高内聚),但是也需避免接口膨胀和过度设计,这是一个权衡。
目标
- 优点:使得系统灵活可扩展,也即使用设计模式的目标
- 缺点:增加系统复杂度、有过度设计的风险
因此适用于系统会不断发生变化或者新老系统共存的场景。
原则
- 隔离变化
- 开(扩展)闭(修改)
- 高内聚/低耦合(High Cohesion/Low Coupling)
- 单一职责(Single Responsibility)
- 面向接口
- 接口隔离:小、高内聚
- 依赖倒置(Dependence Inversion):高层依赖底层、依赖抽象
模式总结
- Strategy:使用接口即使用strategy,用于隔离变化,例如Spring中IOC(依赖反转)。
- Decrator:常见于各种wrapper,常用于在原函数执行前后做一些额外的工作,例如定制输入/输出流、加解密、AOP等。
- Factory Method:隔离创建对象的细节,使得创建对象的行为可扩展,一般配合singleton使用,例如commons的LogFactory。
- Observer:非常实用,即订阅/发布模型,用于事件驱动的设计,例如UI框架中的listener。
- Chain of Responsibility:一组对象按照既定的顺序关联起来,依次处理请求,其中任一对象都有权停止调用的继续传递,例如JavaEE中的Filter。
- Singleton:最简单的模式,但是要注意线程安全的单例模式的几种写法,在延迟加载的场景中:double-check的隐患,以及静态内部类的优点。
- Flyweight:复用变化少的对象,常用于各种资源池的设计,例如线程池,再例如在处理音乐对象时,复用音乐家。
- Adapter:处理遗留系统的不二法宝,也可以用空方法实现接口作为抽象父类,例如Java AWT中的KeyAdapter、MouseAdapter。
- Facade:封装扇出(多个方法的调用简化为一个),复杂的facade可以形成树状结构,本质上是利用树状结构减少调用者的复杂度。
- Template:与多态紧密结合,其实任意的多态使用即为该模式,可以理解为框架与钩子(callback之类)的关系,例如Spring MVC。
- Builder:与factory不同的是,该模式包含了对象构造的若干过程,因此天然地与template结合,例如StringBuilder、protobuf中的builder等。
- Iterator:封装数据的访问行为(顺序、可见性等),一般被容器类创建,例如由Java的Iterable实现类创建。
- Composite:结构上与decorator很像,但可以一个包装多个同接口的实例,在逻辑上也不同,composite将组件组装为整体使用,decorator仅仅是修饰目标的行为,例如目录与文件。
- Command:将行为抽象和解耦,例如绘图命令包含钢笔、笔刷、油漆桶等,每个命令可以包含draw、undo、redo等操作。
- Mediator:对于n个对象,可能共有O(n^2)个联系,使用mediator可以将复杂可变的联系行为封装在该类中,每个对象只需和该类联系即可,例如UI中的组件状态的关联(联动菜单等)。
- State:封装FSM(有限状态机)的状态与状态迁移,每个状态定义了自身的输入与状态迁移,比传统的switch写法更灵活,例如电梯调度。
- Proxy:与decorator在结构上很像,但逻辑上不同,decorator是在原有的基础上做额外的工作,而proxy是原对象的一个完整的替代品,例如图片加载中的占位符、AOP。
- Abstract Factory:该模式抽象出创建一组相关对象的接口,其中每个方法即为factory method,例如创建一组相关的UI控件等。
- Prototype:用于以某个对象为模子创建一个新对象的场景,例如幻灯片中的母版与普通页、对象的克隆(Java中的Cloneable)等。
- Bridge:使用关联代替继承,解决类多维度的扩展导致的类爆炸的问题,例如一本书,从语言上看分为中文英文等(共X种),从类别上分为小说散文等(共Y种),从包装上分为精装平装等(共Z种),那么如果采用继承需要3层共XYZ个类,如果分别包含三种分类的接口,则一共只需X+Y+Z个类。
- Interpreter:很少用到,一般用于解释执行自定义的某种语法,跟command与composite可以合起来使用
举个我在实际工作中用过的例子:规则过滤。该模块输入是仿SQL语法的过滤规则,例如:syndId=101 AND sponsor.id IN (1,2,3) AND campaign.id NOT IN (4,5,6)
可以将一元、二元之类的表达式封装为command,command之间是composite的模式(可以构造为一棵抽象语法树),command本身其实就是不同的interpreter,接受context(实际应用中我是将context与context的求值逻辑分离开了,便于扩展不同的context求值逻辑)作为参数。 - Memento:将当前对象的状态信息保存为另一个对象(状态镜像),使得当前对象可以基于状态镜像快速恢复原状态,例如表单提交后,将已填写正确的字段作为镜像传递给视图层,以便用户继续填写的时候可以只用重写错误的信息。
- Visitor:访问多种类型的元素时,很容易写出if-else的代码,如果类型变化不大但是访问的行为(例如输出元素)容易发生变化时,适合此模式。具体地,为每个元素定义访问行为的接口,在对应的实现中可以调用某个visitor,而visitor的实现类定义具体的实现。例如解析HTML DOM树。
转载信息:链接