分类
常规的分类方式是根据其作用来划分,总共有三类:创建型模式、结构型模式和行为型模式。
创建型模式
该模式提供了一种在创建对象的同时隐藏创建逻辑的方式,不使用new运算符直接实例化对象,它的主要特点是将对象的创建与使用分离
模式 | 功能 |
---|---|
单例模式 | 全局变量 |
简单工厂模式 | 根据参数构造对象,仅仅是对new的封装,不符合开闭原则 |
工厂方法模式 | 以继承的方式,父类定义接口,在子类中构造对象 |
抽象工厂模式 | 相对于工厂方法模式,每个工厂可以构造同一类对象,这一类对象继承自同一个父类 |
原型模式 | 将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例 |
建造者模式 | 将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示 |
创建型模式之间的对比
模式 | 对比 |
---|---|
工厂方法模式 vs 建造者模式 | 工厂方法模式用于创建简单对象,往往一步就可以创建一个完整对象;而建造者模式用于创建相对复杂的对象,需要多个步骤、多次操作来构建一个完整的对象,增加了可定制性和灵活性 |
结构型模式
该模式关注类和对象的组合,即如何将类或对象按某种布局组成更大的结构
模式 | 功能 |
---|---|
装饰模式 | 向现有的对象添加新的功能,同时又不改变其结构,即动态地给一个对象添加一些额外的职责 |
外观模式 | 封装子系统,该封装需要保持不变,子系统可以随意修改,而客户端不会感知 |
组合模式 | 将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性 |
享元模式 | 运用共享技术来有效地支持大量细粒度对象的复用,有点像是一个编程技巧 |
代理模式 | 为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性 |
适配器模式 | 转换接口 |
桥接模式 | 用组合的方式解决子类数量爆炸的问题 |
结构型模式之间的对比
模式 | 对比 |
---|---|
装饰模式 vs 适配器模式 | 装饰器侧重动态的增加功能,而适配器模式只是接口的适配,功能没有变化 |
装饰模式 vs 代理模式 | 两者都可以增强或者削弱被装饰类或者被代理类的能力,但是装饰模式一般采用继承方式实现,会暴露更多的细节。而代理模式采用组合方式,对于调用者而言完全透明,可以有更多的灵活性 |
外观模式 vs 代理模式 | 两者的实现非常像,主要区别在于实现意图,外观模式在于封装,而代理模式在于能力的增强 |
总体来说,上面集中模式比较难以区分,其实实际使用中也不必强行分类,核心是分析业务中稳定部分与不稳定部分。适配器模式,代理模式,外观模式都是将稳定部分抽象成接口,将不稳定部分封装起来。对于装饰模式,我更喜欢将其封装起来,对我提供配置参数,对于调用者而言结构更加简洁。
对于接口设计而言,在实践中悟出道理是:接口要尽可能简洁,能一个方法,就不两个方法,能一个参数,就不两个参数,能一个字母,就不两个字母。因为越是精简,出错的概率就越低。
行为型模式
该模式用于描述类或对象之间怎样通信、协作共同完成任务,以及怎样分配职责。
模式 | 功能 |
---|---|
模板方法模式 | 定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。核心是找到变化点,分离变化到子类中 |
策略模式 | 定义一系列算法,将每个算法封装起来,使它们可以相互替换(同一个功能的不同实现) |
观察者模式 | 多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为,常见的是:发布-订阅 |
命令模式 | 将一个动作封装成一个对象,该对象可以通过函数参数等方法传递和处理 |
迭代器模式 | 提供一种方法来顺序访问(遍历)聚合对象中的一系列数据,而不暴露聚合对象的内部表示 |
状态模式 | 允许一个对象在其内部状态改变时,改变它的行为,对象看起来似乎改成了其他类的对象(行为层面) |
中介者模式 | 定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度 |
备忘录模式 | 在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它,撤销-恢复。如果需要保存对象全部内部状态,采用原型模式更好 |
职责链模式 | 将请求的发送者和接收者解耦,而且接收者是多个,每个接收者记录下一个接收者地址,这样便形成了一条链,请求可以在这条链上传递,并被处理 |
访问者模式 | 允许一个或者多个操作应用到一组对象上,使对象本身和操作解耦 |
解释器模式 | 定义一个语言的文法,并建立一个解释器解释该语言中的句子 |
行为型模式之间的对比
模式 | 对比 |
---|---|
策略模式 vs 访问者模式 | 策略模式的核心思想是将算法的实现和使用分离,客户端可以根据需要选择不同的算法来完成相同的任务。访问者模式的核心思想是将数据结构和数据操作分离,通过访问者来实现对数据的操作。 |
命令模式 vs 职责链模式 | 命令模式的核心思想是将请求封装成一个命令对象,然后由调用者发送命令给接收者来执行。职责链模式的核心思想是将多个处理者组成一条链,每个处理者都有机会处理请求,如果一个处理者无法处理该请求,则将请求传递给下一个处理者。 |
总结
以上设计模式相当于都是具体的套路,其中蕴含的思想及原则才是最为本质和通用的东西,这也正是设计模式所追求的。在使用设计模式过程中,我们需要努力的提炼出一些本质的,共性的内容,把这些共性的内容封装到一起,使其与具体的,特殊的内容分开。核心是发现不变的部分和变化的部分,减少代码的重复,提高代码的扩展能力。在实现手段上往往采用多态的方式。另外,六大原则也是指导合理使用设计模式的利器。
- 单一职责原则
- 开闭原则:对扩展开放,对修改关闭
- 里氏替换原则:任何父类可以出现的地方,子类一定可以出现
- 依赖倒置原则:程序要依赖于抽象接口,不要依赖于具体实现
- 组合复用原则:尽量先使用组合、聚合等关联关系来实现,其次才考虑使用继承关系来实现
- 迪米特法则:一个对象对其他对象的了解尽可能少,从而降低各个对象之间的耦合,即高内聚低耦合。
小提醒
- 当系统的设计不需要预留任何弹性时,就不需要使用模式
- 模式会带来复杂性和降低程序运行效率,除非必要,否则不要着急使用模式
- 设计模式不能解决软件开发中遇到的所有问题
- 不写代码的架构师是值得怀疑的架构师
- 对于大型项目,细致的需求分析和架构设计非常非常重要,特别是需求分析。自顶向下的设计,不要一上来就设计类,应当划分模块(子系统),模块之间的交互逻辑,接口,参数等