常用的设计模式之行为模式
2020-10-26
责任链模式 Chain of Responsibility
责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。
责任链模式适合应用场景
当程序需要使用不同方式处理不同种类请求, 而且请求类型和顺序预先未知时, 可以使用责任链模式。
该模式能将多个处理者连接成一条链。 接收到请求后, 它会 “询问” 每个处理者是否能够对其进行处理。 这样所有处理者都有机会来处理请求。
当必须按顺序执行多个处理者时, 可以使用该模式。
无论你以何种顺序将处理者连接成一条链, 所有请求都会严格按照顺序通过链上的处理者。
如果所需处理者及其顺序必须在运行时进行改变, 可以使用责任链模式。
如果在处理者类中有对引用成员变量的设定方法, 你将能动态地插入和移除处理者, 或者改变其顺序。
命令模式 Command
命令模式是一种行为设计模式, 它可将请求转换为一个包含与请求相关的所有信息的独立对象。 该转换让你能根据不同的请求将方法参数化、 延迟请求执行或将其放入队列中, 且能实现可撤销操作。
命令模式适合应用场景
如果你需要通过操作来参数化对象, 可使用命令模式。
命令模式可将特定的方法调用转化为独立对象。 这一改变也带来了许多有趣的应用: 你可以将命令作为方法的参数进行传递、 将命令保存在其他对象中, 或者在运行时切换已连接的命令等。
举个例子: 你正在开发一个 GUI 组件 (例如上下文菜单), 你希望用户能够配置菜单项, 并在点击菜单项时触发操作。
如果你想要将操作放入队列中、 操作的执行或者远程执行操作, 可使用命令模式。
同其他对象一样, 命令也可以实现序列化 (序列化的意思是转化为字符串), 从而能方便地写入文件或数据库中。 一段时间后, 该字符串可被恢复成为最初的命令对象。 因此, 你可以延迟或计划命令的执行。 但其功能远不止如此! 使用同样的方式, 你还可以将命令放入队列、 记录命令或者通过网络发送命令。
如果你想要实现操作回滚功能, 可使用命令模式。
尽管有很多方法可以实现撤销和恢复功能, 但命令模式可能是其中最常用的一种。
为了能够回滚操作, 你需要实现已执行操作的历史记录功能。 命令历史记录是一种包含所有已执行命令对象及其相关程序状态备份的栈结构。
这种方法有两个缺点。 首先, 程序状态的保存功能并不容易实现, 因为部分状态可能是私有的。 你可以使用备忘录模式来在一定程度上解决这个问题。
其次, 备份状态可能会占用大量内存。 因此, 有时你需要借助另一种实现方式: 命令无需恢复原始状态, 而是执行反向操作。 反向操作也有代价: 它可能会很难甚至是无法实现。
中介者模式 Mediator
中介者模式是一种行为设计模式, 能让你减少对象之间混乱无序的依赖关系。 该模式会限制对象之间的直接交互, 迫使它们通过一个中介者对象进行合作。
中介者模式适合应用场景
当一些对象和其他对象紧密耦合以致难以对其进行修改时, 可使用中介者模式。
该模式让你将对象间的所有关系抽取成为一个单独的类, 以使对于特定组件的修改工作独立于其他组件。
当组件因过于依赖其他组件而无法在不同应用中复用时, 可使用中介者模式。
应用中介者模式后, 每个组件不再知晓其他组件的情况。 尽管这些组件无法直接交流, 但它们仍可通过中介者对象进行间接交流。 如果你希望在不同应用中复用一个组件, 则需要为其提供一个新的中介者类。
如果为了能在不同情景下复用一些基本行为, 导致你需要被迫创建大量组件子类时, 可使用中介者模式。
由于所有组件间关系都被包含在中介者中, 因此你无需修改组件就能方便地新建中介者类以定义新的组件合作方式。
## 访问者模式 Visitor
访问者模式是一种行为设计模式, 它能将算法与其所作用的对象隔离开来。
### 访问者模式适合应用场景
如果你需要对一个复杂对象结构 (例如对象树) 中的所有元素执行某些操作, 可使用访问者模式。
访问者模式通过在访问者对象中为多个目标类提供相同操作的变体, 让你能在属于不同类的一组对象上执行同一操作。
可使用访问者模式来清理辅助行为的业务逻辑。
该模式会将所有非主要的行为抽取到一组访问者类中, 使得程序的主要类能更专注于主要的工作。
当某个行为仅在类层次结构中的一些类中有意义, 而在其他类中没有意义时, 可使用该模式。
你可将该行为抽取到单独的访问者类中, 只需实现接收相关类的对象作为参数的访问者方法并将其他方法留空即可。
## 观察者模式 Observer
观察者模式是一种行为设计模式, 允许你定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象。
### 观察者模式适合应用场景
当一个对象状态的改变需要改变其他对象, 或实际对象是事先未知的或动态变化的时, 可使用观察者模式。
当你使用图形用户界面类时通常会遇到一个问题。 比如, 你创建了自定义按钮类并允许客户端在按钮中注入自定义代码, 这样当用户按下按钮时就会触发这些代码。
观察者模式允许任何实现了订阅者接口的对象订阅发布者对象的事件通知。 你可在按钮中添加订阅机制, 允许客户端通过自定义订阅类注入自定义代码。
当应用中的一些对象必须观察其他对象时, 可使用该模式。 但仅能在有限时间内或特定情况下使用。
订阅列表是动态的, 因此订阅者可随时加入或离开该列表。