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

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

  • 相关阅读:
    mysql数据库分区功能及实例详解
    Mysql线程池优化笔记
    mariadb multi-source replication(mariadb多主复制)
    mysql---二进制日志
    MySQL binlog_format (Mixed,Statement,Row)[转]
    如何生成唯一的server Id,server_id为何不能重复?
    mysql复制过程中的server-id的理解
    MySQL参数:innodb_flush_log_at_trx_commit 和 sync_binlog
    Mysql 用户和权限管理
    B+树索引和哈希索引的区别[转]
  • 原文地址:https://www.cnblogs.com/wenbochang/p/14259772.html
Copyright © 2011-2022 走看看