zoukankan      html  css  js  c++  java
  • 策略模式和模板方法同与异

    前言:

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

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

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

    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:策略模式是将整个算法全部重写,不是部分,而是整体。

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

  • 相关阅读:
    51 Nod 1086 多重背包问题(单调队列优化)
    51 Nod 1086 多重背包问题(二进制优化)
    51 Nod 1085 01背包问题
    poj 2559 Largest Rectangle(单调栈)
    51 Nod 1089 最长回文子串(Manacher算法)
    51 Nod N的阶乘的长度 (斯特林近似)
    51 Nod 1134 最长递增子序列(经典问题回顾)
    51 Nod 1020 逆序排列
    PCA-主成分分析(Principal components analysis)
    Python中cPickle
  • 原文地址:https://www.cnblogs.com/wenbochang/p/14259772.html
Copyright © 2011-2022 走看看