换一种角度:从架构层面来看设计模式(2)
首先,使用策略模式使得架构的边界与使用ifelse编码方式的架构的边界不同。策略模式将代码分成了三部分,这里称为:
而ifelse将代码分成了两部分:
解耦在ifelse实现中,「逻辑流程」和「逻辑实现」是硬编码在一起的,明显的紧耦合。而策略模式将「逻辑流程」和「逻辑实现」拆分开,对其进行了解耦。 解耦后,「逻辑流程」和「逻辑实现」就可以独立的进化,而不会相互影响。 独立进化假设现在要调整业务流程。对于策略模式来说,需要修改的是「逻辑层」;而对于ifelse来说,需要修改的也是「逻辑层」。 假设现在要新增一个策略。对于策略模式来说,需要修改的是「实现层」;而对于ifelse来说,需要修改的还是「逻辑层」。 在软件开发中,有一个原则叫单一职责原则,它不仅仅是针对类或方法的,它也适用于包、模块甚至子系统。 对应到这里,你会发现,ifelse的实现方式违背了单一职责原则。使用ifelse实现,使得逻辑层的职责不单一了。当业务流程需要调整时,需要调整逻辑层的代码;当具体的业务逻辑实现需要调整时,也需要调整逻辑层。 而策略模式将业务流程和具体的业务逻辑拆分到了不同的层内,使得每一层的职责相对的单一,也就可以独立的进化。 对象聚集我们重新来观察一下策略模式的架构图,再对照上面的调用代码,你有没有发现缺少了点什么? 在Client中,我们要根据参数判定来实例化了StategyA或StategyB对象。也就是说,「调用层」使用了「实现层」的代码,实际调用逻辑应该是这样的: 可以看到,Client与StategyA和StategyB是强依赖的。这会导致两个问题:
我们先来解决「对象分散」的问题,下一节来解决「稳定层依赖不稳定层」的问题! 对于「对象分散」的问题来说,创建型的设计模式基本能解决这个问题,对应到这里,可以直接使用工厂方法! 使用了工厂方法后,构建代码被限制在了工厂方法内部,当策略对象的构造逻辑调整时,我们只需要调整对应的工厂方法就可以了。 依赖倒置现在「调用层」只和「实现层」的StategyFactoryImpl有直接的关系,解决了「对象分散」的问题。但是即使只依赖一个类,调用层依然和实现层是强依赖关系。 该如何解决这个问题呢?我们需要依赖倒置。一般方法是使用接口,例如这里的「逻辑层」和「实现层」就是通过接口来实现了依赖倒置:「逻辑层」并不强依赖于「实现层」的任何一个类。箭头方向都是从「实现层」指向「逻辑层」的,所以称为依赖倒置 但是对于「调用层」来说,此方法并不适用,因为它需要实例化具体的对象。那我们该如何处理呢? 相信你已经想到了,就是我们一直在用的IOC!通过注入的方式,使得依赖倒置!我们可以直接替换掉工厂方法。 可以看到,通过依赖注入,使得「调用层」和「实现层」都依赖于「逻辑层」。由于「逻辑层」也是相对较稳定的,所以「调用层」也就不会频繁的变化,现在需要变化的只有「实现层」了。 逻辑显化最后一个区别就是设计模式使得逻辑显化。什么意思呢? 当你使用ifelse的时候,实际上你需要深入到具体的ifelse代码,你才能知道它的具体逻辑是什么。 对于使用设计模式的代码来说,我们回过头来看上面的架构图,从这张图你就能看出来对应的逻辑了:
至于具体的Strategy逻辑是什么样子的,你可以通过类名或方法名来将其显化出来! 总结本文通过将使用设计模式的代码和不使用设计模式的代码分别放到架构中,对比设计模式对架构所产生的影响:
(编辑:ASP站长网) |