【设计模式】聊聊模板模式

原理和实现

设计模式的原理和实现是比较简单的,难的是掌握具体的应用场景和解决什么问题。而模板模式是为来解决复用和拓展两个问题。

模板模式在一个方法中定义好一个算法框架,然后将某些步骤推迟到子类中实现,子类可以在不修改父类流程的时候,实现自己的特有逻辑。

具体code如下。ZkLock定义顶层接口设计,ZkAbstractTemplateLock 实现了基础功能,但是具体的wait和try的流程是固定在ZKlock抽象类中,子类只能根据自己的特性实现对应的方法。

java 复制代码
public interface ZkLock {
    /***
     * 获取锁
     */
    public void zkLock();

    /***
     * 释放锁
     */
    public void zkUnLock();

}


public abstract class ZkAbstractTemplateLock implements ZkLock {

    private static final String ZKSERVER = "192.168.58.138:2181";
    private static final int TIME_OUT = 45 * 100;

    public static final String zkLockPath = "/zkLock";
    public static CountDownLatch countDownLatch = null;

    ZkClient zkClient =  new ZkClient(ZKSERVER,TIME_OUT);

    @Override
    public void zkLock() {
        //模板设计方法 抽象定义在父类中,具体实现由子类来实现
        if (tryLock()){
            System.out.println(Thread.currentThread().getName()+"\t 拿到锁");
        }else {
            waitLock();
            zkLock();
        }
    }

    //将公共的代码抽取到父类中
    public abstract void waitLock();

    /***
     * 尝试获取锁
     * @return
     */
    public abstract boolean tryLock();

    @Override
    public void zkUnLock() {
        if(zkClient!=null){
            zkClient.close();//关闭客户端 node节点自动删除
        }
        System.out.println(Thread.currentThread().getName()+"\t 释放锁成功");
        System.out.println();
    }
}


public class ZkDistributedLock extends ZkAbstractTemplateLock {

    @Override
    public void waitLock() {
        IZkDataListener iZkDataListener = new IZkDataListener() {
            @Override
            public void handleDataChange(String s, Object o) throws Exception {
            }

            //数据被修改 监听Watch
            @Override
            public void handleDataDeleted(String s) throws Exception {
                //如果节点数据删除了 那么countDownLatch减一
                countDownLatch.countDown();
            }
        };

        //在某一个节点上监听事件
        zkClient.subscribeDataChanges(zkLockPath,iZkDataListener);

        //当不为null
        if (zkClient.exists(zkLockPath)){
            countDownLatch = new CountDownLatch(1);//计数1 为0返回
            try {
                //一旦节点被删除 触发事件就执行
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.fillInStackTrace();
            }
        }
        //解除监听器
        zkClient.unsubscribeDataChanges(zkLockPath,iZkDataListener);
    }

    @Override
    public boolean tryLock() {
        try {
            zkClient.createEphemeral(zkLockPath);
            return true;
        }catch (Exception e){
            return false;
        }

    }
}

复用

java inputstream

inputstream 定义了read的基础读取方法,但是也暴露了一个子类可以定制的抽象方法。

java 复制代码
public abstract class InputStream implements Closeable {
    public int read(byte b[], int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }

        int c = read();
        if (c == -1) {
            return -1;
        }
        b[off] = (byte)c;

        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
        }
        return i;
    }

    public abstract int read() throws IOException;

}

java abstractList

abstract class AbstractList 定义了addAll() , 但是留除了一个拓展点给子类,如果子类不实现的话,不能使用。

java 复制代码
    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);
        boolean modified = false;
        for (E e : c) {
            add(index++, e);
            modified = true;
        }
        return modified;
    }
    	
    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }

    //arraylist实现了自己的 add
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

拓展

java servlet

拓展点这里其实是指框架的拓展点,即用户在不修改框架源码的时候,只需要按照框架提高的类进行拓展就可以实现自己的业务逻辑。

小结

模板模式的本质定义一个框架流程,具体的拓展点可以子类进行实现。具体的功能是复用和拓展,复用是指的是,所有的子类可以复用父类中提供的模板方法的代码,拓展是框架通过模板模式提供功能拓展点,用户不修改框架源码的情况下,基于拓展点就可以实现功能。

相关推荐
上趣工作室8 分钟前
uniapp中使用全局样式文件引入的三种方式
开发语言·rust·uni-app
提笔惊蚂蚁14 分钟前
java-web-苍穹外卖-day1:软件开发步骤简化版+后端环境搭建
java·开发语言·前端·程序人生
Ethan Hunt丶14 分钟前
C语言实现IIR型零相位带通滤波器
c语言·开发语言·算法
customer0816 分钟前
【开源免费】基于SpringBoot+Vue.JS美发门店管理系统(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·kafka·开源
Slow菜鸟20 分钟前
SpringBoot教程(二十五) | SpringBoot配置多个数据源
java·spring boot·后端
树懒_Zz22 分钟前
设计模式-状态模式(State)
设计模式·状态模式
孑么30 分钟前
力扣 最小路径和
java·算法·leetcode·职场和发展
geng小球35 分钟前
LeetCode 93-复制 IP地址
java·算法·leetcode
程序员徐师兄38 分钟前
Java基于SpringBoot+Vue框架的宠物寄养系统(V2.0),附源码,文档
java·vue.js·spring boot·毕业设计·宠物寄养系统·宠物寄养
程序员徐师兄41 分钟前
Java基于SpringBoot+Vue的宠物共享平台的设计与实现(附源码,文档)
java·vue.js·spring boot·宠物寄养·宠物共享平台·宠物管理平台