设计模式 14 模板模式

参考源

https://www.bilibili.com/video/BV1u3411P7Na?p=22&vd_source=299f4bc123b19e7d6f66fefd8f124a03


模板模式(Template Pattern)属于行为型模式

概述

在生活中常常会遇到这样的情况,做某一件事情,有些步骤是固定的,有些步骤的变化的。

比如去医院看病,挂号排队这两个步骤是固定的,不管是什么病到了医院都得遵循这两个步骤;但是后续的检查治疗这两个步骤是变化的,不同的病需要采用不同的检查方式,然后采取不同的治疗手段。

针对这一情况,在设计去医院看病这一程序时可以这样实现:定义一个抽象类,固定的步骤用普通方法实现,变化的步骤定义为抽象方法,由子类继承实现。这样就可以根据不同的子类来实现不同的变化步骤,这就是模板模式

代码实现

这里以去医院看病来介绍模板模式:

1、定义抽象疾病

/**  * 疾病  */ public abstract class Disease {      /**      * 治病      */     public void cure() {                  // 1、挂号         registered();         // 2、排队         queue();         // 3、检查         check();         // 4、治疗         treat();     }       /**      * 挂号      */     public void registered() {         System.out.println("1、挂号");     }      /**      * 排队      */     public void queue() {         System.out.println("2、排队");     }      /**      * 检查      */     public abstract void check();      /**      * 治疗      */     public abstract void treat();  } 

2、定义具体疾病

感冒:

/**  * 感冒  */ public class Cold extends Disease {       @Override     public void check() {         System.out.println("3、感冒检查:量体温");     }      @Override     public void treat() {         System.out.println("4、感冒开药:感冒灵");     } } 

口腔溃疡:

/**  * 口腔溃疡  */ public class MouthUlcers extends Disease {       @Override     public void check() {         System.out.println("3、口腔溃疡检查:看口腔");     }      @Override     public void treat() {         System.out.println("4、口腔溃疡开药:西瓜霜");     } } 

3、调用

// 感冒 Disease cold = new Cold(); // 口腔溃疡 Disease mouthUlcers = new MouthUlcers(); // 治疗感冒 cold.cure(); // 治疗口腔溃疡 mouthUlcers.cure(); 

输出结果:

1、挂号 2、排队 3、感冒检查:量体温 4、感冒开药:感冒灵 1、挂号 2、排队 3、口腔溃疡检查:看口腔 4、口腔溃疡开药:西瓜霜 

可以发现,在治疗感冒和口腔溃疡这两种疾病时,前两个步骤是一样的,只有后两个步骤是不同的,这样就实现了复用相同的步骤,后续再定义其他疾病时只需要继承 Disease 实现其抽象方法即可,复用性扩展性都大大提高。

优缺点

优点

1、利用模板方法将相同处理逻辑的代码放到抽象父类中,提高了代码的复用性

2、将不同的代码交由不同的子类实现,通过对子类的扩展增加新的行为,提高代码的扩展性

缺点

1、每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

2、继承关系自身的缺点,如果父类添加新的抽象方法,所有子类都要添加该方法。

使用场景

1、有多个子类共有的方法,且逻辑相同。

2、重要的、复杂的方法,可以考虑作为模板方法。

JUC 中的 AQS 判断是否发布方法 tryRelease 的实现

AbstractQueuedSynchronizer

/**  * 锁释放操作  */ public final boolean release(int arg) {     // 调用 tryRelease 方法判断是否释放锁     // 但是此方法并不是在 AQS 实现的,而是不同的锁自行实现     // 因为 AQS 也不知道你这种类型的锁到底该怎么去解锁     if (tryRelease(arg)) {         Node h = head;         if (h != null && h.waitStatus != 0)             unparkSuccessor(h);         return true;     }     return false; } 
protected boolean tryRelease(int arg) {     throw new UnsupportedOperationException(); } 

ReentrantLock.Sync

protected final boolean tryRelease(int releases) {     int c = getState() - releases;     if (Thread.currentThread() != getExclusiveOwnerThread()) {         throw new IllegalMonitorStateException();     }     boolean free = false;     if (c == 0) {         free = true;         setExclusiveOwnerThread(null);     }     setState(c);     return free; } 

AbstractQueuedSynchronizer 中没有实现 tryRelease ,而是在其子类 ReentrantLock.Sync 中实现。这就是对模板模式的典型应用。

商匡云商
Logo
注册新帐户
对比商品
  • 合计 (0)
对比
0
购物车