设计模式3--模板方法模式(Java并发编程的同步器中用到)

前半部分内容转载自https://blog.csdn.net/carson_ho/article/details/54910518   

模板方法模式:

1.1 定义

定义一个模板结构,将具体内容延迟到子类去实现。

1.2 主要作用

在不改变模板结构的前提下在子类中重新定义模板中的内容。

模板方法模式是基于”继承“的;

1.3 解决的问题
  • 提高代码复用性 
    将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中
  • 实现了反向控制 
    通过一个父类调用其子类的操作,通过对子类的具体实现扩展不同的行为,实现了反向控制 & 符合“开闭原则”

2. 模式原理

2.1 UML类图 & 组成

UML类图

2.2 实例讲解

接下来我用一个实例来对模板方法模式进行更深一步的介绍。 
a. 实例概况

  • 背景:小成希望学炒菜:手撕包菜 & 蒜蓉炒菜心
  • 冲突:两道菜的炒菜步骤有的重复有的却差异很大,记不住
  • 解决方案:利用代码记录下来

b. 使用步骤 

步骤1: 创建抽象模板结构(Abstract Class):炒菜的步骤

public  abstract class Abstract Class {  
//模板方法,用来控制炒菜的流程 (炒菜的流程是一样的-复用)
//申明为final,不希望子类覆盖这个方法,防止更改流程的执行顺序 
        final void cookProcess(){  
        //第一步:倒油
        this.pourOil();
        //第二步:热油
         this.HeatOil();
        //第三步:倒蔬菜
         this.pourVegetable();
        //第四步:倒调味料
         this.pourSauce();
        //第五步:翻炒
         this.fry();
    }  

//定义结构里哪些方法是所有过程都是一样的可复用的,哪些是需要子类进行实现的

//第一步:倒油是一样的,所以直接实现
void pourOil(){  
        System.out.println("倒油");  
    }  

//第二步:热油是一样的,所以直接实现
    void  HeatOil(){  
        System.out.println("热油");  
    }  

//第三步:倒蔬菜是不一样的(一个下包菜,一个是下菜心)
//所以声明为抽象方法,具体由子类实现 
    abstract void  pourVegetable();

//第四步:倒调味料是不一样的(一个下辣椒,一个是下蒜蓉)
//所以声明为抽象方法,具体由子类实现 
    abstract void  pourSauce();


//第五步:翻炒是一样的,所以直接实现
    void fry();{  
        System.out.println("炒啊炒啊炒到熟啊");  
    }  
}

步骤2: 创建具体模板(Concrete Class),即”手撕包菜“和”蒜蓉炒菜心“的具体步骤

//炒手撕包菜的类
  public class ConcreteClass_BaoCai extend  Abstract Class{
    @Override
    public void  pourVegetable(){  
        System.out.println(”下锅的蔬菜是包菜“);  
    }  
    @Override
    public void  pourSauce(){  
        System.out.println(”下锅的酱料是辣椒“);  
    }  
}
//炒蒜蓉菜心的类
  public class ConcreteClass_CaiXin extend  Abstract Class{
    @Override
    public void  pourVegetable(){  
        System.out.println(”下锅的蔬菜是菜心“);  
    }  
    @Override
    public void  pourSauce(){  
        System.out.println(”下锅的酱料是蒜蓉“);  
    }  
}

步骤3: 客户端调用-炒菜了

public class Template Method{
  public static void main(String[] args){

//炒 - 手撕包菜
    ConcreteClass_BaoCai BaoCai = new ConcreteClass_BaoCai();
    BaoCai.cookProcess();

//炒 - 蒜蓉菜心
  ConcreteClass_ CaiXin = new ConcreteClass_CaiXin();
    CaiXin.cookProcess();
    }

}

结果输出

倒油
热油
下锅的蔬菜是包菜
下锅的酱料是辣椒
炒啊炒啊炒到熟

倒油
热油
下锅的蔬菜是菜心
下锅的酱料是蒜蓉
炒啊炒啊炒到熟

3. 优缺点

在全面解析完模板方法模式后,我来分析下其优缺点:

3.1 优点
  • 提高代码复用性 
    将相同部分的代码放在抽象的父类中
  • 提高了拓展性 
    将不同的代码放入不同的子类中,通过对子类的扩展增加新的行为
  • 实现了反向控制 
    通过一个父类调用其子类的操作,通过对子类的扩展增加新的行为,实现了反向控制 & 符合“开闭原则”
3.2 缺点

引入了抽象类,每一个不同的实现都需要一个子类来实现,导致类的个数增加,从而增加了系统实现的复杂度。


4. 应用场景

  • 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现;
  • 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复;
  • 控制子类的扩展。 


在Java并发编程中的同步器:

同步器的设计 是基于模板方法模式的

也就是,使用者需要承同步器并重写指定的方法,随后将同步器方法,随后将同步器合在自定同步件的实现中,并用同步器提供的模板方法,而模板方法将会用使用者重写的方法。

重写同步器指定的方法 ,需要使用同步器提供的如下 3 个方法来 访问 或修改同步状
·getState() 取当前同步状
·setState(int newState) 置当前同步状
·compareAndSetState(int expect,int update) :使用 CAS 置当前状 方法能
置的原子性



同步器提供的模板方法基本上分3

独占式取与放同步状、共享式取与放 同步状查询同步列中的等待线程情况。自定同步件将使用同步器提供的模板方法 实现自己的同步语义


实例:


解释:

独占Mutex是一个自定同步件,它在同一刻只允一个线程占有Mutex中定了一个静内部内部类继承了同步器并实现了独占式取和放同步状

tryAcquire(int acquires)方法中,如果经过CAS置成功(同步状态设1),代表取了同步状,而在tryRelease(int releases)方法中只是将同步状重置0。用使用Mutex并不会直接和内部同步器的实现打交道,而是Mutex提供的方法,在Mutex实现中,以lock()方法例,只需要在方法实现用同步器的模板方法acquire(int args)即可,当线方法取同步状后会被加入到同步列中等待,这样就大大降低了实现一个可靠自定同步件的门槛


内容摘自《Java并发编程的艺术》


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值