策略模式和模板方法同与异

前言:

  最近在写项目的时候,深感设计模式的重要性。一个人的代码写的好不好,别人看的舒不舒服,和会不会设计模式紧密关联的。之前看过四人帮的设计模式。但当时仅限于看,包括现在也仅限于看。有的时候项目中,你都不知道有没有运用到了设计模式。也许用到了单例模式,但你并不知道如何用的,不知不觉就用到了。

  《武林外传》老白曾经说过这样一句话。高手就是手里无刀,心中也无刀。类似于设计模式,你不知不觉中已经融进你的代码中了,但你并不知已经运用了。当然我没有达到这个境界,可能五年,十年,或者更久,谁也说不准呢。

  这次正好趁这个项目,把用到的涉及模式总结一下,策略模式和模板方法模式。

 

1:设计模式分类

总体来说设计模式分为三大类:

创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

我们这次讲的都属于行为型模式。这类模式负责对象间的高效沟通和职责委派。注意理解下对象间,责任委派。

 

2:策略模式

策略模式是一种行为设计模式 它能让你定义一系列算法 并将每种算法分别放入独立的类中 以使算法的对象能够相互替换

在我的项目中有这么一个场景,大家也可以想象一个。用户购买商品支付的时候,可能会使用多种不同的优惠券。比如说,贴息,满减,随机立减等等

这几种返回给前端的金额,文案,以及个个方法都有比较大的差异。我们可以理解为三种不同的算法,选择哪种策略,完全由用户有哪张优惠券所决定的。

因此很简单的,我们可以使用策略模式。

1: 我们首先先定义一个接口

1 @Service
2 public interface CouponStrategy {
3 
4     void execute(Coupon coupon);
5 
6 }

2:定义不同的实现类

 1 class CouponStrategyA implements CouponStrategy {
 2 
 3     @Override
 4     public void execute(Coupon coupon) {
 5         // 第一种具体算法
 6     }
 7     
 8 }
 9 
10 class CouponStrategyB implements CouponStrategy {
11 
12     @Override
13     public void execute(Coupon coupon) {
14         // 第二种具体算法
15     }
16     
17 }

3:我们可以根据coupon选择不同的算法。这里我们可以采用工厂模式

 1 @Service
 2 public class CouponStrategyFactory {
 3 
 4     
 5     private Map<String, CouponStrategy> serviceMap = new HashMap<>();
 6 
 7     
 8     public CouponStrategy getService(CouponInfo couponInfo) {
 9 
10         CouponStrategy couponStrategy = serviceMap.getOrDefault(coupon.getCouponType(), couponDefault);
11 
12         return couponStrategy;
13     }
14 
15 }

最后,这种算法看起来是非常的干净整洁舒服的。比如之前很多type=1,则算法A。type=2则算法B。代码虽然实现,但看起来很难受。

并且策略模式让你能将不同行为抽取到一个独立类层次结构中 并将原始类组合成同一个 从而减少重复代码。比如我可以把A,B,C算法重复的都抽象到interface接口中,代码最重要一点就是避免写重复性的代码。

 

3:模板模式

模板方法模式是一种行为设计模式 它在超类中定义了一个算法的框架 允许子类在不修改结构的情况下重写算法的特定步骤

比如我们JDK经典的ArrayList,用到的就是模板模式,我们看一下他的类图如下:

 

 

这幅图真的特别的经典,可以说是学习模板方法最好的实践了。

ArrayList继承了AbstractList并且实现了多种的接口。ArrayList只实现了自己特定的算法,其余比较通用的算法全部由AbstractList实现。

比如addAll方法, 它位于absract接口。它定义了一系列的算法,比如首先check,在for循环add等等。

但是具体怎么add他并没有实现,而是交由子类去具体实现。

1 public boolean addAll(int index, Collection<? extends E> c) {
2     rangeCheckForAdd(index);
3     boolean modified = false;
4     for (E e : c) {
5         add(index++, e);
6         modified = true;
7     }
8     return modified;
9 }

比如ArrayList的实现

1 public void add(int index, E element) {
2     rangeCheckForAdd(index);
3 
4     ensureCapacityInternal(size + 1);  // Increments modCount!!
5     System.arraycopy(elementData, index, elementData, index + 1,
6                      size - index);
7     elementData[index] = element;
8     size++;
9 }

又比如LinkedList

1 public void add(int index, E element) {
2     checkPositionIndex(index);
3 
4     if (index == size)
5         linkLast(element);
6     else
7         linkBefore(element, node(index));
8 }

类似于子类可以通过钩子操作可以控制父类的行为,是不是很神奇。

最后,当你只希望客户端扩展某个特定算法步骤 而不是整个算法或其结构时 可使用模板方法模式 模板方法将整个算法转换为一系列独立的步骤 以便子类能对其进行扩展 同时还可让超类中所定义的结构保持完整

 

4:策略模式和模板模式同与异

这两种模式非常的相像,一不留神可以分不清楚用那种模式了。当然这就是开头所说的,心中有刀,手里已无刀,你不知不觉中已经融进你的代码中了,但你并不知已经运用了。这其实就是最棒的结果了,但对于咱们初学者,刚开始弄清楚还是有必要的。

相同点:

1: 毋庸置疑都可以减少代码的重复,将重复代码抽象到父类即可。

2: 可以很容易的切换算法,根据前端传来的参数,具体算法何种算法,何种模式。

 

不同点:

1:模板模式基于继承机制 它允许你通过扩展子类中的部分内容来改变部分算法

2:策略模式基于组合机制 你可以通过对相应行为提供不同的策略来改变对象的部分行为 模板方法在类层次上运作 因此它是静态的 策略在对象层次上运作 因此允许在运行时切换行为

3:模板更加看重是算法的流程,全部已经规定好了,子类可以修改部分流程算法

4:策略模式是将整个算法全部重写,不是部分,而是整体。

 

最后祝大家都能写出漂亮,惊艳,眼前一亮的代码。最终做到,手里无刀,心中也无。

 

 

 

 

Tags: