有了代码设计原则,遇到具体情况,就能运用这些原则,设计出代码结构。幸运的是,前人已经为我们总结了常用的设计模式,用来参考。
创建型模式 第一,它们都将系统使用哪些具体类的信息封装起来;第二,它们隐藏了这些类的实例是如何被创建和组织的。
单例模式。
场景。只能有一个实例时的解决方法
抽象工厂模式。
场景。需要创建一系列对象的情况,同时,需求改动时,可能需要创建更多对象。
解决方法。提供个接口,这接口可创建一系列相关或相互依赖的对象。OOP的精华:面向接口编程
建造者模式。
场景。整体由部分按一定方式构成,部分变化会影响构成整体的原方式。如盖楼的步骤一样,各部分材料不同,材料的变化,不会改变盖楼的步骤。
解决方法。把构建整体的方式,与每部分分离开,每部分的变化,不影响构成方式的变化。
简单工厂模式,十分常用。
场景。一个类的创建代码,如果分散在调用的位置,就会有很多相同的创建代码,修改创建代码,需要改很多处;同时,如果多个相似的子类的创建代码,分散在很多位置,加剧了上述相同;另外,采用子类而不是方法代表不同,方便了扩展,扩展时只需添加子类即可,不用为了加方法而改原类。
解决方法。容易变化的用类来实现,代替方法,类的上级可以是普通父类,也可以是接口或抽象类;用工厂类决定创建哪种子类,只需传入参数即可。带来问题是,如果变化太多,用于实现的类会很多,这时,最好使用原型模式,找到各实现类不用的局部点。
原型模式
场景。用简单工厂模式时,新的实现类只改变了一点,但还是要重写一个类,导致了大部分代码相同的实现类很多,改一处,需要改很多实现类。
解决办法。用memberwiseclone方法复制对象,并调用系统方法,实现深拷贝。不同处设值。
结构型模式 讨论的是类和对象的结构,它采用继承机制来组合接口或实现(类结构型模式),或者通过组合一些对象,从而实现新的功能(对象结构型模式)。
适配器模式
场景。希望使用以前的类库等,但原类库的结构,与新功能不匹配,需要转换接口
解决办法。重在转换接口,它能够使原本不能在一起工作的两个类一起工作,所以经常用在类库复用,代码迁移等方面,有一种亡羊补牢的味道。
桥接模式
场景。一个类从各角度考虑,会有很多种层派生类,用继承会把分类设计得很复杂。
解决办法。用组合/聚合,把抽象和实现分类,应用于不是一定用继承的情况。
装饰模式
场景。多次加功能时,带来多次的加子类扩展,各级派生类的组合加剧了这种子类膨胀。
解决办法。动态的给一个对象加额外的职责,即不是给类加功能,而是直接加给对象。
组合模式
场景。一些对象,有的是元对象,有的是用多个元对象组合成的,客户调用时,需要区分是元对象还是组合对象,用不同的方式调用,这增加了耦合度。
解决办法。使用调用组合对象的方式调用,不用管是组合还是元对象。
外观模式
场景。客户系统直接调用一个复杂系统的子系统,当子系统发生变化时,一般会引起调用方式的变化,原因是客户系统与复杂系统的耦合度较高,耦合到了复杂系统的子系统。
解决办法。复杂系统提供一个统一接口,所有复杂系统的子系统与客户系统的通信,都用这个接口,避免复杂系统的内部变化,带来调用方式的变化。
享元模式 平时不常用,一般用于在底层提升性能
场景。 一个系统中有大量对象,耗费大量内存。
解决办法。如果满足其他条件,用享元模式解决。
代理模式
场景。一个对象不能或不希望直接访问其他对象,如远程时不能直接访问,有时直接访问会带来复杂度。
解决办法。加个中间层,类似适配器模式,但不是亡羊补牢,是在避免复杂性,同时保证透明性的情况下加的。
行为型模式
模版方法模式 常用又简单
场景。相同的在子类重复写。
解决办法。 最简单的模式,就是把共性的放到父类,不同的放到子类。
命令模式、
场景。调用对象时,需要做一起其他操作,例如日志,准备参数,事务上的撤销等,为了避免每个调用的位置都重复。
解决办法。把这些调用操作和调用前的准备,以及附加操作,封装到一起,统一管理。
迭代器模式、
场景。集合的遍历式访问,大致一样,可整合成上一个下一个等。
解决办法。所有访问用迭代器
观察者模式、
场景。有的程序需要有一种通知机制,当一个对象变化时,其他对象得到通知,如果设计的不好,就会使这种通知过于紧密耦合。
解决办法。用观察者模式来通知其他一个或多个对象,并更新被通知对象。
中介者模式、
场景。当系统中各模块之间通信时,有时一个模块需要与很多模块通信,如果这样的模块多,会导致通信很复杂。
解决办法。做一个类似主板的类,这个类当中介,总成各个模块间的通信。
备忘录模式、常用
场景。有时需要恢复对象到一个之前的状态,如发生了什么情况,需要恢复。
解决办法。在对象之外,保存对象的各个状态的属性。
解释器模式、
场景。一个复杂公式的计算,可能更复杂到有很多参数,客户程序不用用。
解决办法。进行解释这个公式。
状态模式、
场景。if else(或switch case)语句的增多或者修改)可能会引起很大的修改,而程序的可读性,扩展性也会变得很弱。维护也会很麻烦。
解决办法。用状态模式,看起来是在不同条件下,改变了类,其实是改变了状态
策略模式、类似状态模式
场景。算法增加时,用子类扩展时,if else(或switch case)变得很复杂
解决办法。
职责链模式、
场景。客户程序发出的请求,多个处理程序可处理,但无法确定是哪个程序处理,但一定在这些处理程序里,当这些处理程序发生变化时,客户程序也需要改,这些都增加了客户程序和处理程序之间的耦合度。
解决办法。把客户程序的请求,放到把这些处理程序绑到一起的链子上,不用管谁处理,只需把请求放到链子上即可,链子上的环节变化也不用改客户程序的发出请求方式。
访问者模式。
场景。结构已固定,要加需求,不想改原结构,改原结构用装饰模式小改。
解决办法。类似加入一个访问者,给现结构扩展方法。